Django
Señales
Buscar..
Parámetros
Clase / Método | El porque |
---|---|
UserProfile () Clase | La clase UserProfile amplía el modelo de usuario predeterminado de Django . |
método create_profile () | El método create_profile () se ejecuta, siempre que se post_save señal post_save modelo de usuario de Django. |
Observaciones
Ahora, los detalles.
Las señales de Django son una forma de informar a su aplicación de ciertas tareas (como un modelo antes o después de guardar o eliminar) cuando se lleva a cabo.
Estas señales le permiten realizar acciones de su elección inmediatamente después de que se libera la señal.
Por ejemplo, cada vez que se crea un nuevo Usuario de Django, el Modelo de Usuario emite una señal, con parámetros asociados como sender=User
que le permite dirigir específicamente su escucha de señales a una actividad específica que ocurre, en este caso, una nueva creación de usuario .
En el ejemplo anterior, la intención es tener un objeto UserProfile creado, inmediatamente después de que se crea un objeto User. Por lo tanto, al escuchar una señal post_save
del modelo de User
(el modelo de usuario de Django predeterminado) específicamente, creamos un objeto UserProfile
justo después de crear un nuevo User
.
La documentación de Django proporciona una amplia documentación sobre todas las posibles señales disponibles .
Sin embargo, el ejemplo anterior es explicar en términos prácticos un caso de uso típico cuando se usan señales puede ser una adición útil.
"Con un gran poder viene una gran responsabilidad". Puede ser tentador tener señales dispersas en toda su aplicación o proyecto solo porque son increíbles. Bueno no lo hagas Porque son geniales, no los convierte en la solución de referencia para cada situación simple que se le ocurra.
Las señales son geniales para, como siempre, no todo. Login / Logouts, las señales son geniales. Modelos clave que liberan signos, como el Modelo de Usuario, si está bien.
La creación de señales para todos y cada uno de los modelos en su aplicación puede ser abrumadora en algún momento, y anular la idea general del uso de spjan de Django Signals.
No use señales cuando (según el libro Two Scoops of Django ):
- La señal se relaciona con un modelo en particular y se puede mover a uno de los métodos de ese modelo, posiblemente llamado por
save()
. - La señal se puede reemplazar con un método de administrador de modelos personalizado.
- La señal se relaciona con una vista particular y se puede mover a esa vista
Podría estar bien usar señales cuando:
- Su receptor de señal necesita realizar cambios en más de un modelo.
- Desea enviar la misma señal desde varias aplicaciones y hacer que se manejen de la misma manera por un receptor común.
- Desea invalidar un caché después de guardar un modelo.
- Tiene un escenario inusual que necesita una devolución de llamada, y no hay otra manera de manejarlo además de usar una señal. Por ejemplo, desea activar algo en función del
save()
oinit()
del modelo de una aplicación de terceros. No puede modificar el código de terceros y su extensión podría ser imposible, por lo que una señal proporciona un desencadenante para una devolución de llamada.
Ejemplo de extensión de perfil de usuario
Este ejemplo es un fragmento de código extraído del perfil de usuario de Django como un profesional.
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)
Diferente sintaxis para publicar / pre una señal.
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'):
...
Cómo encontrar si es una inserción o actualización en la señal de pre_save
Al utilizar pre_save
, podemos determinar si una acción de save
en nuestra base de datos fue sobre la actualización de un objeto existente o la creación de uno nuevo.
Para lograr esto, puede verificar el estado del objeto modelo:
@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')
Ahora, cada vez que se realiza una acción de save
, la señal de pre_save
se ejecutará e imprimirá:
-
this is an update
si la acción deriva de una acción de actualización. -
this is an insert
si la acción deriva de una acción de inserción.
Tenga en cuenta que este método no requiere ninguna consulta de base de datos adicional.
Heredando señales en modelos extendidos
Las señales de Django están restringidas a firmas de clase precisas al registrarse, y por lo tanto, los modelos subclasificados no se registran inmediatamente en la misma señal.
Toma este modelo y señal por ejemplo
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 los modelos extendidos, debe adjuntar manualmente la señal en cada subclase, de lo contrario no se verán afectados.
post_save.connect(send_activity_notification, StatusChange)
post_save.connect(send_activity_notification, Comment)
Con Python 3.6, puede aprovechar algunos métodos de clase adicionales construidos en clases para automatizar este enlace.
class Event(models.Model):
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
post_save.connect(send_activity_notification, cls)