Mam model, w którym chciałbym, aby zawierał nazwiska badanych i ich inicjały (dane są nieco anonimizowane i śledzone według inicjałów).
Właśnie teraz napisałem
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)
Jak wskazano w ostatnim wierszu, wolałbym mieć możliwość zapisania inicjałów w bazie danych jako pola (niezależnie od nazwy), ale jest to inicjalizowane wartością domyślną opartą na polu nazwy. Jednak mam problemy, ponieważ modele django nie wydają się mieć „ja”.
Jeśli zmienię linię na subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials)
, mogę wykonać syncdb, ale nie mogę tworzyć nowych tematów.
Czy jest to możliwe w Django, gdy funkcja wywoływalna daje wartość domyślną dla jakiegoś pola na podstawie wartości innego pola?
(Dla ciekawości powodem, dla którego chcę osobno oddzielić inicjały mojego sklepu są rzadkie przypadki, w których dziwne nazwiska mogą mieć inne niż te, które śledzę. Na przykład ktoś inny zdecydował, że inicjały podmiotu 1 o imieniu „John O'Mallory” są „JM” zamiast „JO” i chce naprawić to jako administrator).
źródło
super().save(*args, **kwargs)
(bezSubject, self
argumentów), jak w przykładzie w dokumentacji, do której się odwołuje.Nie wiem, czy istnieje lepszy sposób to zrobić, ale można korzystać z funkcji obsługi sygnału dla tej
pre_save
sygnału :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)
źródło
post_save
zamiastpre_save
.**kwargs
argumentu, który powinny mieć wszystkie funkcje odbiornika zgodnie z docs.djangoproject.com/en/2.0/topics/signals/… ?save()
, być może zmieniona na nadpisywanie__init__
, jest lepsza, ponieważ jest bardziej wyraźna.Korzystanie sygnały Django , można to zrobić dość wcześnie, przyjąwszy na
post_init
sygnał od modelu.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
Sygnał wysyłany jest przez klasę raz miało to miejsce na przykład inicjalizacji. W ten sposób instancja pobiera wartośćname
przed sprawdzeniem, czy jego pola nie dopuszczające wartości null są ustawione.źródło
save()
, być może zmieniona na nadpisywanie__init__
, jest lepsza, ponieważ jest bardziej wyraźna.Jako alternatywną realizację odpowiedzi Gabi Purcaru możesz też podłączyć się do
pre_save
sygnału za pomocąreceiver
dekoratora :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()
Ta funkcja odbiornika przyjmuje również
**kwargs
argumenty słów kluczowych wieloznacznych, które wszystkie programy obsługi sygnału muszą przyjąć zgodnie z https://docs.djangoproject.com/en/2.0/topics/signals/#receiver-functions .źródło