Helpers - компьютеры, интернет, программирование

Как установить значение по умолчанию для поля модели Django для вызова / вызова функции (например, дату относительно времени создания объекта модели)

ИЗМЕНИТЬ:

Как я могу установить в поле Django значение по умолчанию для функции, которая оценивается каждый раз, когда создается новый объект модели?

Я хочу сделать что-то вроде следующего, за исключением того, что в этом коде код оценивается один раз и устанавливает по умолчанию ту же дату для каждого созданного объекта модели, вместо того, чтобы оценивать код каждый раз, когда создается объект модели:

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))



ОРИГИНАЛ:

Я хочу создать значение по умолчанию для параметра функции, чтобы он был динамическим и вызывался и устанавливался каждый раз при вызове функции. Как я могу это сделать? например.,

from datetime import datetime
def mydate(date=datetime.now()):
  print date

mydate() 
mydate() # prints the same thing as the previous call; but I want it to be a newer value

В частности, я хочу сделать это в Django, например,

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))

  • Вопрос сформулирован неправильно: это не имеет ничего общего с значениями параметров функции по умолчанию. Смотрите мой ответ. 29.09.2012
  • Согласно комментарию @ NedBatchelder, я отредактировал свой вопрос (обозначен как EDITED :) и оставил оригинал (обозначен как ORIGINAL :) 02.02.2014

Ответы:


1

Вопрос неверный. При создании поля модели в Django вы не определяете функцию, поэтому значения функции по умолчанию не имеют значения:

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))

Эта последняя строка не определяет функцию; он вызывает функцию для создания поля в классе.

PRE Django 1.7

Django позволяет передавать вызываемый объект по умолчанию, и он будет вызывать его каждый раз, как вы хотите:

from datetime import datetime, timedelta
class MyModel(models.Model):
  # default to 1 day from now
  my_date = models.DateTimeField(default=lambda: datetime.now() + timedelta(days=1))

Django 1.7+

Обратите внимание, что начиная с Django 1.7 использование лямбда в качестве значения по умолчанию не рекомендуется (см. Комментарий @stvnw). Правильный способ сделать это - объявить функцию перед полем и использовать ее как вызываемый объект в default_value с именем arg:

from datetime import datetime, timedelta

# default to 1 day from now
def get_default_my_date():
  return datetime.now() + timedelta(days=1)

class MyModel(models.Model):
  my_date = models.DateTimeField(default=get_default_my_date)

Подробнее в ответе @simanas ниже

29.09.2012
  • Спасибо @NedBatchelder. Это именно то, что я искал. Я не понимал, что «по умолчанию» можно вызвать. И теперь я понимаю, насколько ошибочным был мой вопрос относительно вызова функции и определения функции. 30.09.2012
  • Обратите внимание, что для Django ›= 1.7 использование лямбда-выражений не рекомендуется для параметров поля, поскольку они несовместимы с миграциями. Ссылка: Документы, билет 29.11.2014
  • Снимите отметку с этого ответа, так как он неверен для Djange ›= 1.7. Ответ @Simanas абсолютно правильный, и поэтому его следует принять. 30.03.2015
  • Как это работает с миграциями? Все ли старые объекты получают дату, основанную на времени миграции? Можно ли установить другое значение по умолчанию для использования с миграциями? 07.09.2018
  • Что, если я хочу передать параметр get_default_my_date? 18.10.2018
  • Моя миграция выглядит как ('secret_key', models.CharField(default=core.models.models.getsecretkey, help_text='Hex-encoded secret key to generate totp tokens.', max_length=32, unique=True, validators=[django_otp.util.hex_validator])), и вызывает исключение: AttributeError: module 'django.db.models' has no attribute 'getsecretkey'. Почему миграция ищет getsecretkey() в django.db.models вместо core.models.models для миграции? 03.05.2020

  • 2

    Совершенно неправильно делать это default=datetime.now()+timedelta(days=1)!

    Он оценивается, когда вы запускаете свой экземпляр django. Если вы используете apache, это, вероятно, сработает, потому что в некоторых конфигурациях apache отменяет ваше приложение django при каждом запросе, но все же вы можете найти себя однажды, просматривая свой код и пытаясь выяснить, почему это вычисляется не так, как вы ожидаете .

    Правильный способ сделать это - передать вызываемый объект аргументу по умолчанию. Это может быть функция datetime.today или ваша пользовательская функция. Затем он оценивается каждый раз, когда вы запрашиваете новое значение по умолчанию.

    def get_deadline():
        return datetime.today() + timedelta(days=20)
    
    class Bill(models.Model):
        name = models.CharField(max_length=50)
        customer = models.ForeignKey(User, related_name='bills')
        date = models.DateField(default=datetime.today)
        deadline = models.DateField(default=get_deadline)
    
    08.03.2013
  • Если мое значение по умолчанию основано на значении другого поля в модели, можно ли передать это поле в качестве параметра, например, get_deadline(my_parameter)? 31.03.2015
  • @YPCrumble, это должен быть новый вопрос! 03.05.2016
  • Неа. Это невозможно. Для этого вам придется использовать другой подход. 04.05.2016
  • Как снова удалить поле deadline, одновременно удалив функцию get_deadline? Я удалил поле с функцией для значения по умолчанию, но теперь Django вылетает при запуске после удаления функции. Я мог бы вручную отредактировать миграцию, что в данном случае было бы нормально, но что, если бы вы просто изменили функцию по умолчанию и захотели удалить старую функцию? 09.11.2016

  • 3

    Между следующими двумя конструкторами DateTimeField есть важное различие:

    my_date = models.DateTimeField(auto_now=True)
    my_date = models.DateTimeField(auto_now_add=True)
    

    Если вы используете auto_now_add=True в конструкторе, datetime, на которое ссылается my_date, будет «неизменным» (устанавливается только один раз, когда строка вставляется в таблицу).

    Однако с auto_now=True значение datetime будет обновляться каждый раз при сохранении объекта.

    В какой-то момент для меня это определенно было ловушкой. Для справки, документы здесь:

    https://docs.djangoproject.com/en/dev/ref/models/fields/#datetimefield

    29.09.2012
  • Вы перепутали определения auto_now и auto_now_add, все наоборот. 25.01.2016
  • @MichaelBates теперь лучше? 06.11.2017

  • 4

    Иногда вам может потребоваться доступ к данным модели после создания новой пользовательской модели.

    Вот как я генерирую токен для каждого нового профиля пользователя, используя первые 4 символа их имени пользователя:

    from django.dispatch import receiver
    class Profile(models.Model):
        auth_token = models.CharField(max_length=13, default=None, null=True, blank=True)
    
    
    @receiver(post_save, sender=User) # this is called after a User model is saved.
    def create_user_profile(sender, instance, created, **kwargs):
        if created: # only run the following if the profile is new
            new_profile = Profile.objects.create(user=instance)
            new_profile.create_auth_token()
            new_profile.save()
    
    def create_auth_token(self):
        import random, string
        auth = self.user.username[:4] # get first 4 characters in user name
        self.auth_token =  auth + ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(random.randint(3, 5)))
    
    29.03.2018

    5

    Вы не можете сделать это напрямую; значение по умолчанию оценивается при оценке определения функции. Но есть два пути обойти это.

    Во-первых, вы можете каждый раз создавать (а затем вызывать) новую функцию.

    Или, проще говоря, просто используйте специальное значение, чтобы отметить значение по умолчанию. Например:

    from datetime import datetime
    def mydate(date=None):
      if date is None:
        date = datetime.now()
      print date
    

    Если None - вполне разумное значение параметра и нет другого разумного значения, которое вы могли бы использовать вместо него, вы можете просто создать новое значение, которое определенно выходит за пределы домена вашей функции:

    from datetime import datetime
    class _MyDateDummyDefault(object):
      pass
    def mydate(date=_MyDateDummyDefault):
      if date is _MyDateDummyDefault:
        date = datetime.now()
      print date
    del _MyDateDummyDefault
    

    В некоторых редких случаях вы пишете метакод, который действительно должен принимать абсолютно все, даже, скажем, mydate.func_defaults[0]. В этом случае вам нужно сделать что-то вроде этого:

    def mydate(*args, **kw):
      if 'date' in kw:
        date = kw['date']
      elif len(args):
        date = args[0]
      else:
        date = datetime.now()
      print date
    
    29.09.2012
  • Обратите внимание, что нет никаких причин для фактического создания экземпляра класса фиктивного значения - просто используйте сам класс как фиктивное значение. 29.09.2012
  • Вы МОЖЕТЕ сделать это напрямую, просто передав функцию вместо результата вызова функции. См. Мой опубликованный ответ. 29.09.2012
  • Нет, не можешь. Результат функции отличается от обычных параметров, поэтому его нельзя разумно использовать в качестве значения по умолчанию для этих обычных параметров. 29.09.2012
  • Ну да, если вы передадите объект вместо функции, это вызовет исключение. То же самое верно, если вы передаете функцию в параметр, ожидающий строку. Я не понимаю, насколько это актуально. 29.09.2012
  • Это актуально, потому что его функция myfunc заставлена ​​принимать (и печатать) datetime; вы изменили его, поэтому его нельзя использовать таким образом. 29.09.2012
  • Я не знал, что нам не разрешили изменять способ использования функции. Мой способ работает отлично, он просто требует, чтобы вы передали функцию вместо даты, что так же (или более) элегантно, чем использование значения-заполнителя. 29.09.2012
  • Это даже не так элегантно. Мое решение оставляет API как есть; ваш заменяет его чем-то необычным и непифоничным. Вот почему вы видите код, похожий на мой, повсюду в стандартной библиотеке, а код, подобный вашему, нигде. 29.09.2012

  • 6

    Передайте функцию как параметр вместо передачи результата вызова функции.

    То есть вместо этого:

    def myfunc(date=datetime.now()):
        print date
    

    Попробуй это:

    def myfunc(date=datetime.now):
        print date()
    
    29.09.2012
  • Это не работает, потому что теперь пользователь не может фактически передать параметр - вы попытаетесь вызвать его как функцию и выбросить исключение. В этом случае вы можете просто взять без параметров и print datetime.now() безоговорочно. 29.09.2012
  • Попробуй. Вы не передаете дату, вы передаете функцию datetime.now. 29.09.2012
  • Да, по умолчанию передается функция datetime.now. Но любой пользователь, который передает значение, отличное от значения по умолчанию, будет передавать дату и время, а не функцию. foo = datetime.now(); myfunc(foo) поднимет TypeError: 'datetime.datetime' object is not callable. Если бы я действительно хотел использовать вашу функцию, мне пришлось бы вместо этого сделать что-то вроде myfunc(lambda: foo), что не является разумным интерфейсом. 29.09.2012
  • Я не считаю неразумным иметь интерфейс, требующий переданной функции. Пользователь должен будет передать объект, генерирующий дату, а не дату. Итак, для примера lambda: datetime.now () + timedelta (days = 1). 29.09.2012
  • Я даже не знаю, что на это сказать. Никто не будет ожидать такого интерфейса или ему нравится, или помнить, как его использовать. Это просто глупо. 29.09.2012
  • Интерфейсы, которые принимают функции, не являются чем-то необычным. Если хотите, я мог бы начать называть примеры из Python stdlib. 29.09.2012
  • Да, функции высшего порядка берут на себя функции. Функции даты принимают даты. time.strftime, например, не принимает функцию, возвращающую время, и str.__add__ не принимает функцию, возвращающую строку. 29.09.2012
  • Здесь задавался вопрос: сгенерировать значение для заполнения поля даты, а не функцию даты. Я бы согласился, если бы вы писали библиотеку дат, но это не так. 29.09.2012
  • Он явно пытается написать повседневную, обычную функцию с повседневным, обычным интерфейсом, за исключением того, что он хочет, чтобы по умолчанию было что-то динамическое. Вы заменили его чем-то другим, которое нельзя использовать таким же образом. Вы действительно думаете, что интерфейс models.DateTimeField ожидает (или должен ожидать) функцию, которая возвращает дату, а не дату? 29.09.2012
  • Нет, я так не думаю. Мне все равно, каково фактическое поведение DateTimeField по умолчанию, вы заметите, что ни одно из наших решений не будет работать там легко, поскольку нам обоим нужно изменить поведение этого объекта (ваше решение для интерпретации значения заполнителя, мое для принятия функция.) И если вы все равно собираетесь переопределить это поведение, вы можете заставить свой интерфейс ожидать все, что вы хотите. 29.09.2012
  • Django уже принимает вызываемый объект именно так, как предполагает этот вопрос. 29.09.2012
  • Новые материалы

    Интуитивное понимание тензоров в машинном обучении
    Тензор является важной концепцией во многих научных областях, таких как математика, физика, обработка сигналов и компьютерное зрение, и это лишь некоторые из них. В математике тензор — это..

    Использование машинного обучения для диагностики болезни Альцгеймера, часть 4
    Маркеры семантической согласованности для ранней диагностики болезни Альцгеймера (arXiv) Автор: Давиде Колла , Маттео Дельсанто , Марко Агосто , Бенедетто Витиелло , Даниэле Паоло Радичони..

    Почему объяснимость так важна прямо сейчас?
    По мере того, как системы искусственного интеллекта и инструменты на основе машинного обучения распространяются в нашей повседневной жизни, как практики, так и критики все чаще заявляют о..

    Анимированный математический анализ
    Использование Manim для создания математических анимированных визуализаций Визуализация данных помогает понять скрытые закономерности в данных, которые невозможно визуализировать..

    Создание простого слайдера изображений с помощью JavaScript
    Узнайте, как создать базовый слайдер изображений с помощью HTML, CSS и JavaScript. Введение В этом уроке мы создадим удобный слайдер изображений, используя JavaScript, HTML и CSS. Ползунок..

    Создание базы данных с помощью супергероя «Python»
    В этом посте мы узнаем, как создать «базу данных SQLite с помощью модуля python sqlite3, создав простую функцию входа и регистрации. Готовы ли вы к этому путешествию? Если да , давайте приступим..

    ИИ для чайников: руководство для начинающих по пониманию будущего технологий
    Вы чувствуете, что остались позади в мире ИИ? Не волнуйтесь, вы не одиноки! Со всей этой шумихой вокруг искусственного интеллекта может быть трудно понять, с чего начать. Но не позволяйте сленгу..