Django
Signale
Suche…
Parameter
Klasse / Methode | Das Warum |
---|---|
UserProfile () Klasse | Die UserProfile-Klasse erweitert das Standardbenutzermodell von Django . |
Methode create_profile () | Die create_profile () -Methode wird ausgeführt, wenn ein post_save Signal eines Django-Benutzermodells freigegeben wird . |
Bemerkungen
Nun zu den Details.
Mit Django-Signalen können Sie Ihre App über bestimmte Aufgaben informieren (z. B. vor oder nach dem Speichern oder Löschen eines Modells), wenn sie ausgeführt werden.
Mit diesen Signalen können Sie Aktionen Ihrer Wahl ausführen, sobald das Signal ausgelöst wird.
Jedes Mal , wenn ein neuer Django-Benutzer erstellt wird, gibt das Benutzermodell ein Signal aus, wobei Parameter wie sender=User
sodass Sie das Abhören von Signalen gezielt auf eine bestimmte Aktivität ausrichten können, die in diesem Fall eine neue Benutzererstellung ist .
Im obigen Beispiel soll ein UserProfile-Objekt erstellt werden, unmittelbar nachdem ein User-Objekt erstellt wurde. post_save
wir speziell auf ein post_save
Signal des User
(das standardmäßige Django-Benutzermodell) hören, erstellen wir ein UserProfile
Objekt, unmittelbar nachdem ein neuer User
erstellt wurde.
Die Django-Dokumentation bietet eine umfassende Dokumentation aller verfügbaren Signale .
Das obige Beispiel soll jedoch in praktischer Hinsicht erklären, dass ein typischer Anwendungsfall bei der Verwendung von Signalen eine nützliche Ergänzung sein kann.
"Mit großer Macht kommt große Verantwortung". Es kann verlockend sein, Signale über Ihre gesamte App oder Ihr Projekt zu verteilen, nur weil sie großartig sind. Gut nicht. Weil sie cool sind, sind sie nicht die Lösung für jede einfache Situation, die Ihnen in den Sinn kommt.
Die Signale sind wie üblich großartig für alles. Anmelden / Abmelden, Signale sind großartig. Schlüsselmodelle, die Zeichen wie das Benutzermodell freigeben, sofern in Ordnung.
Das Erstellen von Signalen für jedes einzelne Modell in Ihrer App kann an einem bestimmten Punkt überwältigend werden und die ganze Idee der Sparring-Verwendung von Django-Signalen zunichte machen.
Verwenden Sie keine Signale, wenn (basierend auf dem Two Scoops of Django-Buch ):
- Das Signal bezieht sich auf ein bestimmtes Modell und kann in eine der Methoden dieses Modells verschoben werden, die möglicherweise von
save()
aufgerufen werden. - Das Signal kann durch eine benutzerdefinierte Modellmanager-Methode ersetzt werden.
- Das Signal bezieht sich auf eine bestimmte Ansicht und kann in diese Ansicht verschoben werden
Es kann in Ordnung sein, Signale zu verwenden, wenn:
- Ihr Signalempfänger muss Änderungen an mehreren Modellen vornehmen.
- Sie möchten dasselbe Signal von mehreren Apps ausgeben und von einem gemeinsamen Empfänger auf dieselbe Weise behandeln lassen.
- Sie möchten einen Cache nach dem Speichern eines Modells ungültig machen.
- Sie haben ein ungewöhnliches Szenario, für das ein Rückruf erforderlich ist, und es gibt keine andere Möglichkeit, als nur ein Signal zu verwenden. Sie möchten beispielsweise etwas auslösen, das auf dem
save()
oder deminit()
des Modells einer Drittanbieter-App basiert. Sie können den Code des Drittanbieters nicht ändern. Das Erweitern des Codes ist möglicherweise nicht möglich. Daher gibt ein Signal einen Auslöser für einen Rückruf aus.
Beispiel für ein Benutzerprofil erweitern
Dieses Beispiel ist ein Ausschnitt aus dem Extending Django User Profile wie ein Profi
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)
Andere Syntax, um ein Signal zu posten / vorzugeben
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'):
...
So finden Sie heraus, ob es sich um ein Insert oder ein Update im pre_save-Signal handelt
Mit pre_save
wir feststellen, ob es sich bei einer save
in unserer Datenbank darum handelt, ein vorhandenes Objekt zu aktualisieren oder ein neues zu erstellen.
Um dies zu erreichen, können Sie den Zustand des Modellobjekts überprüfen:
@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')
Jedes Mal, wenn eine save
wird, wird das Signal pre_save
ausgeführt und gedruckt:
-
this is an update
wenn die Aktion von einer Aktualisierungsaktion abgeleitet wurde. -
this is an insert
wenn die Aktion von einer Einfügeaktion abgeleitet wurde.
Beachten Sie, dass diese Methode keine zusätzlichen Datenbankabfragen erfordert.
Vererbung von Signalen bei erweiterten Modellen
Die Signale von Django sind bei der Registrierung auf genaue Klassensignaturen beschränkt, so dass Unterklassenmodelle nicht sofort auf demselben Signal registriert werden.
Nehmen Sie dieses Modell und signalisieren Sie es zum Beispiel
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)
Bei erweiterten Modellen müssen Sie das Signal manuell an jede Unterklasse anhängen, andernfalls werden sie nicht beeinflusst.
post_save.connect(send_activity_notification, StatusChange)
post_save.connect(send_activity_notification, Comment)
Mit Python 3.6 können Sie einige zusätzliche Klassenmethoden für Klassen nutzen, um diese Bindung zu automatisieren.
class Event(models.Model):
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
post_save.connect(send_activity_notification, cls)