Django
segnali
Ricerca…
Parametri
Classe / Metodo | Il perché |
---|---|
UserProfile () Class | La classe UserProfile estende il modello utente predefinito Django . |
metodo create_profile () | Il metodo create_profile () viene eseguito ogni volta che viene rilasciato un segnale post_save modello utente Django. |
Osservazioni
Ora, i dettagli.
I segnali Django sono un modo per informare la tua app di determinati compiti (come un modello pre o post-salvataggio o eliminazione) quando ha luogo.
Questi segnali ti consentono di eseguire azioni a tua scelta immediatamente che il segnale viene rilasciato.
Ad esempio, ogni volta che viene creato un nuovo utente Django, il Modello utente rilascia un segnale, associando parametri come sender=User
consente di indirizzare in modo specifico l'ascolto dei segnali a un'attività specifica che si verifica, in questo caso, una nuova creazione utente .
Nell'esempio precedente, l'intenzione è di creare un oggetto Profilo utente creato immediatamente dopo la creazione di un oggetto Utente. Pertanto, ascoltando specificamente un segnale post_save
dal modello User
(il modello utente Django predefinito), creiamo un oggetto UserProfile
subito dopo la creazione di un nuovo User
.
La documentazione di Django fornisce un'ampia documentazione su tutti i possibili segnali disponibili .
Tuttavia, l'esempio sopra riportato è quello di spiegare in termini pratici un tipico caso d'uso quando si usano i segnali come un'aggiunta utile.
"Con un grande potere viene una grande responsabilità". Può essere allettante avere segnali sparsi per l'intera app o progetto solo perché sono fantastici. Bene, non farlo. Perché sono cool non li rende la soluzione ideale per ogni situazione semplice che viene in mente.
I segnali sono ottimi, come al solito, non tutto. Login / Logout, i segnali sono fantastici. Modelli chiave che rilascino segnali, come il Modello utente, se disponibili.
La creazione di segnali per ogni modello della tua app può diventare travolgente a un certo punto e sconfiggere l'intera idea dell'uso sparring di Django Signals.
Non usare segnali quando (basato su Two Scoops of Django book ):
- Il segnale si riferisce a un modello particolare e può essere spostato in uno dei metodi di quel modello, eventualmente chiamato da
save()
. - Il segnale può essere sostituito con un metodo di gestione modello personalizzato.
- Il segnale si riferisce a una vista particolare e può essere spostato in quella vista
Potrebbe essere normale usare i segnali quando:
- Il ricevitore del segnale deve apportare modifiche a più di un modello.
- Vuoi inviare lo stesso segnale da più app e farle gestire allo stesso modo da un ricevitore comune.
- Si desidera invalidare una cache dopo un salvataggio del modello.
- Hai uno scenario insolito che richiede una richiamata e non c'è altro modo per gestirlo oltre a utilizzare un segnale. Ad esempio, si desidera attivare qualcosa in base al
save()
oinit()
del modello di un'app di terze parti. Non è possibile modificare il codice di terze parti ed estenderlo potrebbe essere impossibile, quindi un segnale fornisce un trigger per un callback.
Estensione dell'esempio del profilo utente
Questo esempio è uno snippet tratto dal profilo utente Django esteso come un Pro
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)
Sintassi diversa per postare / pre un segnale
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'):
...
Come trovare se si tratta di un inserimento o di un aggiornamento nel segnale pre_save
Utilizzando il pre_save
possiamo determinare se un'azione di save
sul nostro database riguardava l'aggiornamento di un oggetto esistente o la creazione di uno nuovo.
Per ottenere ciò è possibile controllare lo stato dell'oggetto modello:
@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')
Ora ogni volta che viene eseguita un'azione di save
, il segnale pre_save
verrà eseguito e stamperà:
-
this is an update
se l'azione deriva da un'azione di aggiornamento. -
this is an insert
se l'azione deriva da un'azione di inserimento.
Si noti che questo metodo non richiede query di database aggiuntive.
Ereditare i segnali sui modelli estesi
I segnali di Django sono limitati a precise firme di classe al momento della registrazione, e quindi i modelli sottoclasse non vengono immediatamente registrati sullo stesso segnale.
Prendi questo modello e segnala per esempio
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)
Con i modelli estesi, è necessario collegare manualmente il segnale su ciascuna sottoclasse altrimenti non verranno effettuati.
post_save.connect(send_activity_notification, StatusChange)
post_save.connect(send_activity_notification, Comment)
Con Python 3.6, puoi sfruttare alcuni metodi di classe aggiuntivi incorporati in classi per automatizzare questa associazione.
class Event(models.Model):
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
post_save.connect(send_activity_notification, cls)