【问题标题】:Consolidating multiple post_save signals with one receiver用一个接收器合并多个 post_save 信号
【发布时间】:2013-07-04 16:08:26
【问题描述】:

所以我阅读了 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...

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

post_save.connect(fn_name, model_name)

对于我拥有的每个模型。有没有更好的方法来使用新的 Django 1.5 @receiver 装饰器功能?

【问题讨论】:

    标签: django


    【解决方案1】:

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

    post_save.connect(foo)
    
    def foo(sender, **kwargs):
        if sender not in [FooModel, BarModel]:
            return
        ... actual code ...
    

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

    def foo(sender, **kwargs):
        if not getattr(sender, 'process_by_foo', False):
            return
        ... actual code ...
    

    【讨论】:

      【解决方案2】:

      根据Django documentation on receivers默认情况下,接收者不需要连接到特定的发送者。所以你描述的是默认的 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 ...
      

      这假设模型看起来像:

      class Rebel(models.Model):
          ...
      
      class Stormtrooper(models.Model):
          ...
      
      class Battleground(models.Model):
          ...
      

      【讨论】:

      • 这个接收器不会也被每个其他模型的 post_save 调用吗?这可能是很多电话......
      • @nivcaner 是的,这就是问题所要求的:使用一个post_save 来监听多个模型的变化
      • @TylerHayes 多个模型与所有模型不一样
      • @DylanYoung 是的。答案被标记为已接受。如果提问者认为这不再是他们问题的最佳答案,欢迎他们进行更改。
      • 如果您将模型列表设为{'rebel', 'stormtrooper'} 之类的集合,in 语句将是 O(1) 而不是 O(N),这不会比多次注册更复杂在现在接受的答案中;额外的好处是list_of_models 可以在设置中定义或计算。所以竖起大拇指,谢谢@Tyler Hayes!
      【解决方案3】:

      您可以使用@receiver decorator

      from django.dispatch import 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
      

      【讨论】:

      • 这应该是公认的答案,尽管可以使用自定义装饰器使其更加干燥。
      • 可能更干燥;但是,我认为在这种情况下,这会损害清晰度。
      • 问题的最佳答案
      • 同意@freethebees。这清楚地表明有多个发件人。自定义装饰器会隐藏这个事实(如果只是暂时的)。
      • 所需的导入是from django.dispatch import receiver
      【解决方案4】:
      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
      

      【讨论】:

      • 这应该是公认的答案。像魅力一样工作。
      • 对不起,使用情况如何?可以举个例子吗?
      猜你喜欢
      • 2015-08-03
      • 2016-03-23
      • 2023-03-24
      • 2020-10-21
      • 2013-10-21
      • 1970-01-01
      • 2018-03-05
      • 2017-04-06
      • 1970-01-01
      相关资源
      最近更新 更多