2010-04-27 30 views
114

我剛剛開始在django項目中實現信號偵聽器。雖然我明白他們是什麼以及如何使用它們。我很難弄清楚我應該把它們放在哪裏。從Django的網站上的文檔中有這樣一段話:信號處理程序應該在django項目中生活?

Where should this code live?

你可以把信號處理和 註冊碼任何你喜歡的。 但是,您需要確保它所在的模塊 早於 開啓,以便在發送任何需要發送的信號 之前,信號處理得到 。這使得您的應用程序的 models.py成爲 註冊信號處理程序的好地方。

雖然它的一個很好的建議,在我的models.py中有非模型類或方法只是歪曲我的方式。

那麼,存儲和註冊信號處理程序的最佳做法/規則是什麼?

回答

34

我其實喜歡讓它們成爲模型本身的類方法。這樣可以將一切都保存在一個類中,並且意味着您不必擔心導入任何內容。

+0

導入模型我喜歡這一點。謝謝! – 2010-04-27 14:12:57

+2

你通常在哪裏連接處理程序的信號? – DataGreed 2010-12-28 17:42:54

+1

@DataGreed:位於相關models.py的底部。 – 2010-12-28 19:05:10

13

我剛剛閱讀this關於佈局項目/應用程序的最佳實踐的文章,並且它建議您所有的自定義調度程序信號都應放在名爲signals.py的文件中。但是,這並不能完全解決您的問題,因爲您仍然需要將這些文件導入到某個地方,並且越早導入它們就越好。

模型建議是一個很好的建議。由於您已經在signals.py文件中定義了所有內容,因此文件頂部不應超過一行。這類似於admin.py文件的佈局方式(類定義在頂部,所有自定義管理類在底部註冊的代碼),如果您定義了信號然後將它們連接到同一個文件中。

希望有幫助!最終,它歸結爲你喜歡的。

+0

我也想把我的信號處理程序放在'signals.py'文件中,但不知道應該如何調用它。通過在我的'models.py'文件中導入它,我得到了一個非常乾淨的解決方案,沒有「污染」我的models.py文件。謝謝! :) – 2011-07-22 15:54:07

+9

有一個交叉導入那裏:signals.py嘗試從models.py – 2011-08-05 16:27:58

39

我只是剛剛遇到這個問題,而且由於我的信號與模型無關,所以我想添加我的解決方案。

我記錄了登錄/註銷周圍的各種數據,並且需要掛鉤到django.contrib.auth.signals

我已經把信號處理成signals.py文件,然後導入的信號從__init__.py模塊文件,因爲我相信這是因爲應用程序啓動後立即調用(用print聲明測試表明,它甚至在所謂的設置文件被讀取。)

# /project/__init__.py 
import signals 

和signals.py

# /project/signals.py 
from django.contrib.auth.signals import user_logged_in 

def on_logged_in(sender, user, request, **kwargs): 
    print 'User logged in as: \'{0}\''.format(user) 

user_logged_in.connect(on_logged_in) 

我很新的Django的(/蟒蛇),因此是對所有人開放的,告訴我,這是一個可怕的想法!

+3

這種感覺很符合邏輯,但我建議在應用程序級別進行此操作。 – Nils 2012-07-28 03:11:13

+2

小心,這個邏輯很可能會導致重複信號發射。 'user_logged_in.connect(on_logged_in)'應該很可能傳入'dispatch_uid'參數。更多信息請參見https://docs.djangoproject。COM/EN /開發/主題/信號/#防止重複的-信號。 – 2013-04-23 00:25:38

+0

謝謝你 - 很高興知道。我使用這種方法記錄所有登錄(記錄IP /用戶代理),並且迄今沒有任何重複記錄 - 儘管這並不意味着線路上的小改變不會導致問題! – 2013-04-23 10:01:52

6

models.py和信號。py在每個應用程序中都是推薦連接信號的地方,但是,在我看來,它們並不是最好的解決方案,以保持信號和處理程序的派遣。調度應該是django發明信號和處理程序的原因。

我一直在掙扎很久,最後我們想出瞭解決辦法。

在應用程序的文件夾

創建連接器模塊,從而我們有:

app/ 
    __init__.py 
    signals.py 
    models.py 
    connectors.py 
在app/connectors.py

,我們定義的信號處理程序和連接它們。提供一個例子:

from signals import example_signal 
from models import ExampleModel 
from django.db.models.signals import post_save, post_delete 

def hanndler(sender, *args, **kwargs): 
    pass 

post_save.connect(hander, sender=ExampleModel) 

然後在models.py,我們添加下面一行在文件的結尾:

from app import connector 

一切都在這裏完成。

通過這種方式,我們可以將signals.py中的信號以及connectors.py中的所有處理程序。模型和信號沒有混亂。

希望它提供了另一種解決方案。

+0

那麼在signals.py中會發生什麼?看起來像你的例子,它只是自定義信號。通常我們只是將信號和連接器組合起來,因爲大多數都不會有自定義信號 – dalore 2013-07-11 10:50:54

+0

@dalore是的,所有自定義信號都放在signals.py中。我們有許多定製信號。但是,如果你沒有太多,這個文件可以省略。 – samuel 2013-08-30 02:45:00

179

將其加入到documentationDjango的1.7發佈:

嚴格地說,信號處理和註冊碼可以住在任何地方你喜歡,雖然它的建議,以避免應用程序的根模塊和模型模塊以最小化導入代碼的副作用。

實際上,信號處理程序通常是在它們相關的應用程序的信號子模塊中定義的。信號接收器連接在應用程序配置類的ready()方法中。如果您使用的是receiver()裝飾器,只需在ready()中導入信號子模塊。

在Django 1.7中更改:由於ready()在先前版本的Django中不存在,因此信號註冊通常發生在models模塊中。

最佳做法是在信號子模塊的handlers.py中定義處理程序,例如,

yourapp /信號/ handlers.py

from django.db.models.signals import pre_save 
from django.dispatch import receiver 
from myapp.models import MyModel 

@receiver(pre_save, sender=MyModel) 
def my_handler(sender, **kwargs): 
    pass 

註冊信號處理程序的最佳位置是那麼定義它的應用程序的AppConfig中,使用,看起來像一個文件準備好()方法。這將是這樣的:

yourapp/apps.py

from django.apps import AppConfig 

class TasksConfig(AppConfig): 
    name = 'tasks' 
    verbose_name = "Tasks" 

    def ready(self): 
     import yourproject.yourapp.signals.handlers #noqa 

確保您直接在您的settings.py的INSTALLED_APPS指定,要麼加載你的AppConfig,或在__init__的你的應用。有關更多信息,請參閱see the ready() documentation

注意:如果您也爲其他應用程序也提供了信號以偵聽,請將它們放入信號模塊中的__init__,例如,看起來像一個文件然後

yourapp /信號/ __ init__.py

import django.dispatch 

task_generate_pre_save = django.dispatch.Signal(providing_args=["task"]) 

另一個應用程序可以通過導入並對其進行註冊,例如聽你的信號from yourapp.signals import task_generate_pre_save。從你的處理程序分離你的信號保持乾淨。

說明的Django 1.6:

如果你仍然停留在Django的1.6或更低,那麼你會做同樣的事情(在yourapp /信號/ handlers.py定義處理程序),而是比使用AppConfig,你會通過你的應用的__init__.py加載處理程序,例如是這樣的:

yourapp/__ init__.py

import signals 

這並不像你一樣使用就緒()方法,因爲它往往會造成圓形的進口問題。

+3

作爲documentaiton說你重寫準備好了,你可能想要做一些像 super(ReportsConfig,self).ready(),以防django決定使用某些東西來填充ready()(從1.7.0開始,它現在是空的) – 2014-10-04 19:00:04

+2

我認爲這個答案是最好的,因爲它是解決進口副作用的唯一辦法。我來這裏尋找最佳實踐,因爲我正在清理一個應用程序,這完全是由於這種副作用造成的。唉,應用程序在django 1.6上運行,最佳實踐只能在django 1.7上運行。讓'__init__'導入信號暫時的解決方法不適用於我,所以我想知道是否有另一個地方可以導入信號,直到我們準備升級到更高版本的django。 – kasperd 2014-11-17 14:45:39

+0

不應該有'來自。在'yourapp/signals/__ init __。py'中導入處理程序(或類似的)? – dhobbs 2015-06-03 19:29:01

0

我把它們放在一個單獨的文件中signals.py,在models.py之後所有的模型都被定義了。我導入它們並將模型連接到信號。

signals.py

# necessary imports 

def send_mail_on_save(<args>): 
    # code here 

models.py

# imports 
class mymodel(models.Model): 
    # model here 

# import signals 
from signals import send_mail_on_save 
# connect them 
post_save.connect(send_mail_on_save,sender=mymodel) 

這爲我提供了邏輯分離,當然沒有什麼錯在他們留在models.py,但更這種方式可以管理。

希望這有助於!