trigger - señales django
Consolidando múltiples señales post_save con un receptor (4)
Puede omitir el nombre de model_name
y se conectará a todos los modelos post_save. Luego puede filtrar si está en el modelo correcto en el controlador:
post_save.connect(foo)
def foo(sender, **kwargs):
if sender not in [FooModel, BarModel]:
return
... actual code ...
o puede filtrar según el campo en el modelo:
def foo(sender, **kwargs):
if not getattr(sender, ''process_by_foo'', False):
return
... actual code ...
Así que leí el código fuente de Django (post 1.5) que ahora puede registrar múltiples señales múltiples en una función de receptor:
def receiver(signal, **kwargs):
"""
A decorator for connecting receivers to signals. Used by passing in the
signal (or list of signals) and keyword arguments to connect::
@receiver(post_save, sender=MyModel)
def signal_receiver(sender, **kwargs):
...
@receiver([post_save, post_delete], sender=MyModel)
def signals_receiver(sender, **kwargs):
...
"""
... implementation code...
Sin embargo, quiero registrar múltiples señales post_save de diferentes remitentes a la misma función. En este momento, acabo de llamar
post_save.connect(fn_name, model_name)
Para cada modelo que tengo. ¿Hay una mejor manera de hacer esto con la nueva capacidad de decorador Django 1.5 @receiver?
Puedes usar eso usando el decorador @receiver:
@receiver(post_save, sender=Model1)
@receiver(post_save, sender=Model2)
@receiver(post_save, sender=Model3)
def my_signal_handle(sender , **kwargs)
# some code here
Según la documentación de Django sobre los receptores , los receptores por defecto no necesitan estar conectados a un remitente específico . Entonces, lo que estás describiendo es la funcionalidad predeterminada de Django.
En otras palabras, para hacer esto usando el decorador @receiver
simplemente no especificas un remitente en el decorador. Por ejemplo:
@receiver(post_save) # instead of @receiver(post_save, sender=Rebel)
def set_winner(sender, instance=None, created=False, **kwargs):
list_of_models = (''Rebel'', ''Stormtrooper'', ''Battleground'')
if sender.__name__ in list_of_models: # this is the dynamic part you want
if created: # only run when object is first created
... set the winner ...
Esto supone modelos que parecen:
class Rebel(models.Model):
...
class Stormtrooper(models.Model):
...
class Battleground(models.Model):
...
def receiver_with_multiple_senders(signal, senders, **kwargs):
"""
Based on django.dispatch.dispatcher.receiver
Allows multiple senders so we can avoid using a stack of
regular receiver decorators with one sender each.
"""
def decorator(receiver_func):
for sender in senders:
if isinstance(signal, (list, tuple)):
for s in signal:
s.connect(receiver_func, sender=sender, **kwargs)
else:
signal.connect(receiver_func, sender=sender, **kwargs)
return receiver_func
return decorator