2013-07-06 4 views
24

Так что я прочитал исходный код Django (Post 1.5), что теперь вы можете зарегистрировать несколько несколько сигналов функции приемника:Объединение нескольких сигналов post_save с одним приемником

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?

ответ

89

Вы можете использовать, что с помощью @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 
+1

Это должен быть принятый ответ, хотя его можно сделать более сухим с помощью специального декоратора. – DylanYoung

+4

Это может быть более СУХОЙ; однако, я думаю, что это будет в ущерб ясности в этом случае. – freethebees

+0

Лучший ответ на вопрос –

18

Вы можете пропустить 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 ... 
29

согласно 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): 
    ... 
+6

не этот приемник также дозвонились на * каждый * post_save другой модели? это может быть много звонков ... – nivcaner

+0

@nivcaner да вот что задавал вопрос: используйте один 'post_save' для прослушивания изменений на нескольких моделях –

+2

@TylerHayes несколько моделей не то же самое, что и все модели – DylanYoung