Sygnały Django a nadpisywanie metody zapisu

89

Mam problem ze zrozumieniem tego. W tej chwili mam kilka modeli, które wyglądają mniej więcej tak:

 def Review(models.Model)
    ...fields...
    overall_score = models.FloatField(blank=True)

def Score(models.Model)
    review = models.ForeignKey(Review)
    question = models.TextField()
    grade = models.IntegerField()

Recenzja składa się z kilku „wyników”, ogólny wynik jest średnią ocen. Kiedy zapisywana jest recenzja lub ocena, muszę ponownie obliczyć średnią ogólną ocenę. W tej chwili używam zastąpionej metody zapisywania. Czy byłoby jakieś korzyści z używania dyspozytora sygnału Django?

imjoevasquez
źródło

Odpowiedzi:

84

Sygnały zapisywania / usuwania są ogólnie korzystne w sytuacjach, w których trzeba wprowadzić zmiany, które nie są całkowicie specyficzne dla danego modelu lub można je zastosować do modeli, które mają coś wspólnego lub można je skonfigurować do użycia w różnych modelach.

Jednym z typowych zadań w zastępowanych savemetodach jest automatyczne generowanie informacji o pracy z jakiegoś pola tekstowego w modelu. To jest przykład czegoś, co, jeśli trzeba by go zaimplementować dla wielu modeli, skorzystałoby na użyciu pre_savesygnału, w którym program obsługi sygnału mógłby wziąć nazwę pola informacji o pracy i nazwę pola, z którego ma wygenerować informacje o pracy. Gdy już masz coś takiego, każda wprowadzona ulepszona funkcjonalność będzie miała również zastosowanie do wszystkich modeli - np. Wyszukanie ślimaka, który masz zamiar dodać dla danego typu modelu, aby zapewnić wyjątkowość.

Aplikacje wielokrotnego użytku często czerpią korzyści z wykorzystania sygnałów - jeśli dostarczaną przez nie funkcjonalność można zastosować do dowolnego modelu, generalnie (chyba że jest to nieuniknione) nie będą chcieli, aby użytkownicy musieli bezpośrednio modyfikować swoje modele, aby z nich skorzystać.

Z Django mptt , na przykład, użyłem pre_savesygnału zarządzać zestaw pól opisujących strukturę drzewa dla modelu, który ma zamiar być tworzone lub aktualizowane i pre_deletesygnał do usunięcia drzew szczegóły konstrukcji dla obiektu przed usunięciem i całej jego poddrzewo obiektów znajdujących się przed nim i są one usuwane. Ze względu na użycie sygnałów, użytkownicy nie muszą dodawać ani modyfikować saveani deletemetod w swoich modelach, aby wykonać to zarządzanie, po prostu muszą poinformować django-mptt, którymi modelami chcą zarządzać.

Jonny Buchanan
źródło
Co się stanie, jeśli program obsługi sygnału wyzwoli wyjątek? Przypuszczam, że nie powinny wywoływać wyjątków, bo inaczej nie pasują. Czy się mylę?
x-yuri
20

Zapytałeś:

Czy byłoby jakieś korzyści z używania dyspozytora sygnału Django?

Znalazłem to w dokumentacji django:

Zastąpione metody modelu nie są wywoływane w operacjach zbiorczych

Należy zauważyć, że metoda delete () dla obiektu niekoniecznie jest wywoływana podczas zbiorczego usuwania obiektów przy użyciu QuerySet lub w wyniku usuwania kaskadowego. Aby zapewnić wykonanie dostosowanej logiki usuwania, możesz użyć sygnałów pre_delete i / lub post_delete.

Niestety, nie ma obejścia podczas zbiorczego tworzenia lub aktualizowania obiektów, ponieważ żadne metody save (), pre_save i post_save nie są wywoływane.

Od: nadpisywanie predefiniowanych metod modelu

guettli
źródło
3
Widok listy administratorów Django używa usuwania zbiorczego ... był zdezorientowany, dopóki nie natknął się na tę ciekawostkę.
N.Balauro,
7
jest tam również napisane „Niestety, nie ma obejścia podczas zbiorczego tworzenia lub aktualizowania obiektów, ponieważ żadne metody save (), pre_save i post_save nie są wywoływane”. - więc nie sądzę, że jest to kompromis między tymi metodami.
Cory
Dotyczy to obu metod, więc odpowiedź brzmi: „nie, nie ma korzyści z używania sygnałów w przeciwieństwie do nadpisywania savemetody”?
Flimm
3

Jeśli użyjesz sygnałów, będziesz mógł aktualizować wynik recenzji za każdym razem, gdy powiązany model oceny zostanie zapisany. Ale jeśli nie potrzebuję takiej funkcjonalności, nie widzę żadnego powodu, aby umieszczać to w sygnale, to całkiem związane z modelem.

Dmitrij Szewczenko
źródło
2

To rodzaj denormalizacji. Spójrz na to ładne rozwiązanie . Definicja pola kompozycji w miejscu.

Alex Koshelev
źródło
1

Mały dodatek z dokumentacji Django o usuwaniu zbiorczym ( .delete()metoda na QuerySetobiektach):

Należy pamiętać, że jeśli to możliwe, będzie to wykonywane wyłącznie w języku SQL, a zatem metody delete () poszczególnych instancji obiektów niekoniecznie będą wywoływane podczas tego procesu. Jeśli podałeś niestandardową metodę delete () w klasie modelu i chcesz mieć pewność, że jest ona wywoływana, będziesz musiał „ręcznie” usunąć wystąpienia tego modelu (np. Poprzez iterację po QuerySet i wywołanie funkcji delete () w każdego obiektu z osobna), zamiast używać metody usuwania zbiorczego () QuerySet.

https://docs.djangoproject.com/en/1.11/topics/db/queries/#deleting-objects

I zbiorcza aktualizacja ( .update()metoda na QuerySetobiektach):

Wreszcie, zdaj sobie sprawę, że update () wykonuje aktualizację na poziomie SQL, a zatem nie wywołuje żadnych metod save () w twoich modelach, ani nie emituje sygnałów pre_save ani post_save (które są konsekwencją wywołania Model.save ( )). Jeśli chcesz zaktualizować kilka rekordów dla modelu, który ma niestandardową metodę save (), zapętl je i wywołaj save ()

https://docs.djangoproject.com/en/2.1/ref/models/querysets/#update

valex
źródło
Czy to nie dotyczy obu?
Flimm