У меня есть модель, в которой я хотел бы содержать имена субъектов и их инициалы (данные несколько анонимны и отслеживаются по инициалам).
Прямо сейчас я написал
class Subject(models.Model):
name = models.CharField("Name", max_length=30)
def subject_initials(self):
return ''.join(map(lambda x: '' if len(x)==0 else x[0],
self.name.split(' ')))
# Next line is what I want to do (or something equivalent), but doesn't work with
# NameError: name 'self' is not defined
subject_init = models.CharField("Subject Initials", max_length=5, default=self.subject_initials)
Как указано в последней строке, я бы предпочел, чтобы инициалы фактически сохранялись в базе данных в виде поля (независимо от имени), но оно инициализируется значением по умолчанию на основе поля имени. Однако у меня возникают проблемы, так как модели django, похоже, не имеют «я».
Если я изменю строку на subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials)
, то смогу выполнить syncdb, но не смогу создавать новые темы.
Возможно ли это в Django, если вызываемая функция дает значение по умолчанию для некоторого поля на основе значения другого поля?
(Для любопытных, причина, по которой я хочу разделить инициалы своего магазина отдельно, заключается в редких случаях, когда странные фамилии могут отличаться от тех, которые я отслеживаю. Например, кто-то другой решил, что инициалы Субъекта 1 с именем «Джон О'Мэллори» являются "JM", а не "JO", и хочет исправить, отредактируйте его как администратор.)
источник
super().save(*args, **kwargs)
(безSubject, self
аргументов), как в примере в указанной документации.Я не знаю , если есть лучший способ сделать это, но вы можете использовать обработчик сигнала для по
pre_save
сигналу :from django.db.models.signals import pre_save def default_subject(sender, instance, using): if not instance.subject_init: instance.subject_init = instance.subject_initials() pre_save.connect(default_subject, sender=Subject)
источник
post_save
вместоpre_save
.**kwargs
аргумент, который должен иметь все функции-получатель согласно docs.djangoproject.com/en/2.0/topics/signals/… ?save()
, возможно, измененный на переопределение__init__
, лучше, поскольку он более явный.Используя сигналы Django , это может быть сделано достаточно рано, получив на
post_init
сигнале от модели.from django.db import models import django.dispatch class LoremIpsum(models.Model): name = models.CharField( "Name", max_length=30, ) subject_initials = models.CharField( "Subject Initials", max_length=5, ) @django.dispatch.receiver(models.signals.post_init, sender=LoremIpsum) def set_default_loremipsum_initials(sender, instance, *args, **kwargs): """ Set the default value for `subject_initials` on the `instance`. :param sender: The `LoremIpsum` class that sent the signal. :param instance: The `LoremIpsum` instance that is being initialised. :return: None. """ if not instance.subject_initials: instance.subject_initials = "".join(map( (lambda x: x[0] if x else ""), instance.name.split(" ")))
post_init
Сигнал посылается по классу , как только он сделал инициализации на экземпляре. Таким образом, экземпляр получает значение,name
прежде чем проверять, установлены ли его поля, не допускающие значения NULL.источник
save()
, возможно, измененный на переопределение__init__
, лучше, поскольку он более явный.В качестве альтернативной реализации ответа Габи Пуркару вы также можете подключиться к
pre_save
сигналу с помощьюreceiver
декоратора :from django.db.models.signals import pre_save from django.dispatch import receiver @receiver(pre_save, sender=Subject) def default_subject(sender, instance, **kwargs): if not instance.subject_init: instance.subject_init = instance.subject_initials()
Эта функция приемника также принимает
**kwargs
аргументы ключевого слова с подстановочными знаками, которые должны принимать все обработчики сигналов в соответствии с https://docs.djangoproject.com/en/2.0/topics/signals/#receiver-functions .источник