Поле модели Django по умолчанию основано на другом поле в той же модели
У меня есть модель, в которой я хотел бы указать название темы и ее инициалы. (Данные несколько анонимны и отслеживаются инициалами.)
Прямо сейчас, я написал
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 названа "John O'Mallory" Инициалы - это "JM", а не "JO", и вы хотите исправить его как администратора.)
Ответы
Ответ 1
Модели, безусловно, имеют "я"! Просто вы пытаетесь определить атрибут класса модели как зависящий от экземпляра модели; это невозможно, поскольку экземпляр не существует (и не может) существовать до того, как вы определите класс и его атрибуты.
Чтобы получить нужный эффект, переопределите метод save() класса модели. Внесите необходимые изменения в необходимый экземпляр, затем вызовите метод суперкласса для фактической экономии. Вот краткий пример.
def save(self, *args, **kwargs):
if not self.subject_init:
self.subject_init = self.subject_initials()
super(Subject, self).save(*args, **kwargs)
Это описано в Переопределение методов модели в документации.
Ответ 2
Я не знаю, есть ли лучший способ сделать это, но вы можете использовать обработчик сигналов для сигнал 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)