使用一个接收器整合多个post_save信号

fan*_*err 41 django

所以我读了Django源代码(后1.5),你现在可以将多个多个信号注册到接收函数:

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...
Run Code Online (Sandbox Code Playgroud)

但是,我想将来自不同发送者的多个post_save信号注册到同一个函数.现在,我只是打电话

post_save.connect(fn_name, model_name)
Run Code Online (Sandbox Code Playgroud)

对于我拥有的每个型号.使用新的Django 1.5 @receiver装饰器功能有更好的方法吗?

hub*_*ert 130

您可以使用@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
Run Code Online (Sandbox Code Playgroud)

  • 它可能更干; 但是,我认为这会损害这种情况的清晰度. (11认同)
  • 这应该是公认的答案,尽管使用自定义装饰器可以使其更加干燥。 (2认同)

Tyl*_*yes 30

根据关于接收器Django文档,默认情况下接收器不需要连接到特定的发送器.所以你所描述的是默认的Django功能.

换句话说,要使用@receiver装饰器执行此操作,您只需在装饰器中不指定发件人.例如:

@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 ...
Run Code Online (Sandbox Code Playgroud)

假设模型看起来像:

class Rebel(models.Model):
    ...

class Stormtrooper(models.Model):
    ...

class Battleground(models.Model):
    ...
Run Code Online (Sandbox Code Playgroud)

  • 这个接收器也不会被调用*每个*其他模型的post_save?这可能是很多电话...... (8认同)
  • @TylerHayes的多个型号与所有型号不一样 (8认同)
  • 如果您将模型列表设置为像“{'rebel', 'stormtrooper'}”这样的集合,则“in”语句将是 O(1) 而不是 O(N),这并不比多个注册更复杂在现在接受的答案中;额外的好处是“list_of_models”可以在设置中定义或计算。所以对这个竖起大拇指,谢谢@Tyler Hayes! (2认同)

Tom*_*cki 19

您可以跳过,model_name然后连接到所有模型post_save.然后你可以过滤你在处理程序中的正确模型:

post_save.connect(foo)

def foo(sender, **kwargs):
    if sender not in [FooModel, BarModel]:
        return
    ... actual code ...
Run Code Online (Sandbox Code Playgroud)

或者您可以根据模型中的字段进行过滤:

def foo(sender, **kwargs):
    if not getattr(sender, 'process_by_foo', False):
        return
    ... actual code ...
Run Code Online (Sandbox Code Playgroud)


C S*_*C S 15

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
Run Code Online (Sandbox Code Playgroud)