Szukaj…


Parametry

Klasa / metoda Dlaczego
Klasa UserProfile () Klasa UserProfile rozszerza domyślny model użytkownika Django .
Metoda create_profile () Metoda create_profile () jest wykonywana za każdym razem, gdy zostaje zwolniony sygnał post_save modelu użytkownika Django.

Uwagi

Teraz szczegóły.

Sygnały Django to sposób na poinformowanie aplikacji o określonych zadaniach (takich jak zapisywanie lub usuwanie lub usuwanie modelu), kiedy ma miejsce.

Sygnały te pozwalają wykonać wybrane czynności natychmiast po zwolnieniu sygnału.

Na przykład, za każdym razem, gdy tworzony jest nowy użytkownik Django, model użytkownika uwalnia sygnał, z powiązaniem parametrów, takich jak sender=User umożliwiając ukierunkowanie odsłuchu sygnałów na konkretne działanie, które ma miejsce, w tym przypadku, tworzenie nowego użytkownika .

W powyższym przykładzie intencją jest utworzenie obiektu UserProfile natychmiast po utworzeniu obiektu User. Dlatego słuchając sygnału post_save z modelu User (domyślnego modelu użytkownika Django), tworzymy obiekt UserProfile zaraz po utworzeniu nowego User .

Dokumentacja Django zawiera obszerną dokumentację wszystkich możliwych sygnałów .

Jednak powyższy przykład ma na celu wyjaśnienie w praktyce typowego przypadku użycia, gdy użycie Sygnałów może być użytecznym dodatkiem.

"Z dużą mocą przychodzi duża odpowiedzialność". Może być kuszące, aby sygnały były rozproszone w całej aplikacji lub projekcie tylko dlatego, że są niesamowite. Nie rób tego. Ponieważ są fajne, nie sprawiają, że są idealnym rozwiązaniem dla każdej prostej sytuacji, jaka przychodzi na myśl.

Sygnały świetnie nadają się, jak zwykle, nie do wszystkiego. Logowanie / wylogowanie, sygnały są świetne. Kluczowe modele zwalniające znaki, takie jak model użytkownika, jeśli są w porządku.

Tworzenie sygnałów dla każdego modelu w Twojej aplikacji może stać się przytłaczające w jednym momencie i pokonać cały pomysł sparingowego użycia sygnałów Django.

Nie używaj sygnałów, gdy (na podstawie książki Two Scoops of Django ):

  • Sygnał dotyczy jednego konkretnego modelu i może zostać przeniesiony do jednej z metod tego modelu, prawdopodobnie wywołanej przez save() .
  • Sygnał można zastąpić niestandardową metodą menedżera modeli.
  • Sygnał dotyczy określonego widoku i może zostać przeniesiony do tego widoku

Użycie sygnałów może być prawidłowe, gdy:

  • Twój odbiornik sygnału musi wprowadzić zmiany w więcej niż jednym modelu.
  • Chcesz wysłać ten sam sygnał z wielu aplikacji i obsługiwać je w ten sam sposób przez wspólny odbiornik.
  • Chcesz unieważnić pamięć podręczną po zapisaniu modelu.
  • Masz nietypowy scenariusz, który wymaga oddzwonienia i nie ma innego sposobu na poradzenie sobie z nim poza użyciem sygnału. Na przykład chcesz uruchomić coś w oparciu o save() lub init() modelu aplikacji innej firmy. Nie można modyfikować kodu innej firmy, a jego rozszerzenie może być niemożliwe, więc sygnał wyzwala wywołanie zwrotne.

Przykład rozszerzenia profilu użytkownika

Ten przykład jest fragmentem wziętym z Rozszerzającego profilu użytkownika Django, podobnie jak profesjonalista

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
 
class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='user')
    website = models.URLField(default='', blank=True)
    bio = models.TextField(default='', blank=True)

def create_profile(sender, **kwargs):
    user = kwargs["instance"]
    if kwargs["created"]:
        user_profile = UserProfile(user=user)
        user_profile.save()
post_save.connect(create_profile, sender=User)

Inna składnia do wysyłania / poprzedzania sygnału

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
 
class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='user')
    website = models.URLField(default='', blank=True)
    bio = models.TextField(default='', blank=True)

@receiver(post_save, sender=UserProfile)
def post_save_user(sender, **kwargs):
    user = kwargs.get('instance')
    if kwargs.get('created'):
        ...

Jak sprawdzić, czy jest to wstawka lub aktualizacja w sygnale pre_save

Korzystając z pre_save możemy ustalić, czy akcja save w naszej bazie danych dotyczyła aktualizacji istniejącego obiektu czy utworzenia nowego.

Aby to osiągnąć, możesz sprawdzić stan obiektu modelu:

    @receiver(pre_save, sender=User)
    def pre_save_user(sender, instance, **kwargs): 
        if not instance._state.adding:
            print ('this is an update')
        else:
            print ('this is an insert')

Teraz za każdym razem, gdy save akcja ma miejsca, pre_save sygnał będzie działać i będzie drukować:

  • this is an update jeśli akcja pochodzi z akcji aktualizacji.
  • this is an insert jeśli akcja pochodzi z akcji wstawiania.

Pamiętaj, że ta metoda nie wymaga żadnych dodatkowych zapytań do bazy danych.

Dziedziczenie sygnałów w modelach rozszerzonych

Sygnały Django są ograniczone do dokładnych podpisów klas podczas rejestracji, a zatem modele podklas nie są natychmiast rejestrowane na tym samym sygnale.

Weźmy na przykład ten model i sygnał

class Event(models.Model):
    user = models.ForeignKey(User)


class StatusChange(Event):
    ...


class Comment(Event):
    ...


def send_activity_notification(sender, instance: Event, raw: bool, **kwargs):
    """
    Fire a notification upon saving an event
    """

    if not raw:
        msg_factory = MessageFactory(instance.id)
        msg_factory.on_activity(str(instance))
post_save.connect(send_activity_notification, Event)

W przypadku modeli rozszerzonych należy ręcznie dołączyć sygnał do każdej podklasy, w przeciwnym razie nie zostanie to zrealizowane.

post_save.connect(send_activity_notification, StatusChange)
post_save.connect(send_activity_notification, Comment)

W Pythonie 3.6 możesz wykorzystać dodatkowe metody klas wbudowane w klasy, aby zautomatyzować to wiązanie.

class Event(models.Model):

    @classmethod
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        post_save.connect(send_activity_notification, cls)


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow