Dokumentacja Django zawiera tylko przykłady przesłaniania save()
i delete()
. Chciałbym jednak zdefiniować dodatkowe przetwarzanie dla moich modeli tylko wtedy, gdy są tworzone . Dla każdego, kto zna Railsy, byłoby to równoznaczne z utworzeniem :before_create
filtru. czy to możliwe?
django
django-models
django-forms
ground5hark
źródło
źródło
create
? To ciekawe rozwiązanie, ale nie działałoby w przypadkach, gdy obiekt jest tworzony przy użyciuObject(**kwargs).save()
lub jakiejkolwiek innej odmiany tego.super(MyModel, self).save(*args, **kwargs)
?self.pk
czy nie jest najlepszym sposobem sprawdzenia, czy obiekt jest nowo tworzony, czy tylko aktualizowany. Czasami podajesz identyfikator obiektu w czasie tworzenia (dostosowaną wartość, która nie została wygenerowana przez bazę danych, np.KSUID
) I spowoduje to, że ta klauzula nigdy nie zostanie wykonana ... Istniejeself._state.adding
wartość, aby upewnić się, czy zapisuje się po raz pierwszy, czy tylko aktualizuje, co pomaga w takich przypadkach.przykład tworzenia sygnału post_save (z http://djangosnippets.org/snippets/500/ )
from django.db.models.signals import post_save from django.dispatch import receiver @receiver(post_save, sender=User) def create_profile(sender, instance, created, **kwargs): """Create a matching profile whenever a user object is created.""" if created: profile, new = UserProfile.objects.get_or_create(user=instance)
tutaj jest przemyślana dyskusja na temat tego, czy najlepiej używać sygnałów, czy niestandardowych metod zapisywania https://web.archive.org/web/20120815022107/http://www.martin-geber.com/thought/2007/10/29/ django-signal-vs-custom-save-method /
Moim zdaniem użycie sygnałów do tego zadania jest solidniejsze, łatwiejsze do odczytania, ale dłuższe.
źródło
instance.save()
. Tak więc w tym przypadku występuje również spadek wydajności, ponieważ do bazy danych zostanie wysłane jedno zapytanie INSERT i jedno zapytanie UPDATE.To jest stare, ma akceptowaną odpowiedź, która działa (Zach) i bardziej idiomatyczną (Michaela Bylstry), ale ponieważ jest to nadal pierwszy wynik w Google, który większość ludzi widzi, myślę, że potrzebujemy więcej najlepszych praktyk modern-django stylowa odpowiedź tutaj :
from django.db.models.signals import post_save class MyModel(models.Model): # ... @classmethod def post_create(cls, sender, instance, created, *args, **kwargs): if not created: return # ...what needs to happen on create post_save.connect(MyModel.post_create, sender=MyModel)
Chodzi o to:
@classmethod
zamiast,@staticmethod
ponieważ najprawdopodobniej będziesz musiał odwoływać się do statycznych członków klasy w kodzieJeszcze czystsze byłoby, gdyby rdzeń Django miał rzeczywisty
post_create
sygnał. (Imho, jeśli musisz przekazać argument logiczny, aby zmienić zachowanie metody, powinny to być 2 metody).źródło
Aby odpowiedzieć na to pytanie dosłownie,
create
metoda w menadżerze modelu jest standardowym sposobem tworzenia nowych obiektów w Django. Aby zastąpić, zrób coś takiegofrom django.db import models class MyModelManager(models.Manager): def create(self, **obj_data): # Do some extra stuff here on the submitted data before saving... # For example... obj_data['my_field'] = my_computed_value(obj_data['my_other_field']) # Now call the super method which does the actual creation return super().create(**obj_data) # Python 3 syntax!! class MyModel(models.model): # An example model my_field = models.CharField(max_length=250) my_other_field = models.CharField(max_length=250) objects = MyModelManager()
W tym przykładzie nadpisuję metodę
create
metody Managera, aby wykonać dodatkowe przetwarzanie przed faktycznym utworzeniem instancji.UWAGA: Kod jak
my_new_instance = MyModel.objects.create(my_field='my_field value')
wykona tę zmodyfikowaną
create
metodę, ale kod podobny domy_new_unsaved_instance = MyModel(my_field='my_field value')
nie będzie.
źródło
Zastępowanie
__init__()
umożliwi wykonanie kodu podczas tworzenia wystąpienia modelu. Nie zapomnij zadzwonić do rodziców__init__()
.źródło
Możesz zastąpić metodę create za pomocą niestandardowego menedżera lub dodać metodę classmethod do klasy modelu. https://docs.djangoproject.com/en/1.11/ref/models/instances/#creating-objects
źródło
Preferowana odpowiedź jest poprawna, ale test sprawdzający, czy obiekt jest tworzony, nie działa, jeśli model pochodzi z UUIDModel. Pole pk będzie już miało wartość.
W takim przypadku możesz to zrobić:
already_created = MyModel.objects.filter(pk=self.pk).exists()
źródło