信号处理程序应该放在django项目中的哪个位置?

时间:2010-04-27 05:56:53

标签: django signal-handling

我刚开始在django项目中实现信号侦听器。虽然我明白它们是什么以及如何使用它们。我很难搞清楚应该放在哪里。来自django网站的文档可以这样说:

  

Where should this code live?

     

你可以把信号处理和   注册码随时随地。   但是,您需要确保这一点   它所在的模块很早就被导入了   因此,信号处理得到   在任何信号需要之前注册   被发送。这使你的应用程序   models.py是个好地方   注册信号处理程序。

虽然这是一个很好的建议,但在我的models.py中使用非模型类或方法只会让我误解错误。

那么,存储和注册信号处理程序的最佳实践/规则是什么?

7 个答案:

答案 0 :(得分:218)

Django 1.7 发布时,这已添加到documentation

  

严格地说,信号处理和注册代码可以在任何你喜欢的地方生活,尽管建议避免应用程序的根模块及其模型模块,以尽量减少导入代码的副作用。

     

实际上,信号处理程序通常定义在与其相关的应用程序的信号子模块中。信号接收器在应用程序配置类的ready()方法中连接。如果你正在使用receiver()装饰器,只需在ready()中导入信号子模块。

     

在Django 1.7中更改:由于在早期版本的Django中不存在ready(),因此信号注册通常发生在模型模块中。

最佳做法是在信号子模块中的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

注册信号处理程序的最佳位置是使用 ready()方法定义它的应用程序的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或应用的__init__中指定AppConfig。有关详细信息,请参阅see the ready() documentation

注意:如果您还为其他应用提供了收听信号,请将它们放入信号模块中的__init__,例如一个看起来像这样的文件:

yourapp /信号/ __初始化__。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 / signals / handlers.py中定义你的处理程序),而不是使用AppConfig,你会加载处理程序通过您的应用程序的__init__.py,例如类似的东西:

yourapp / __初始化__。PY

import signals

这与使用ready()方法一样好,因为它经常导致循环导入问题。

答案 1 :(得分:39)

我实际上喜欢让它们成为模型本身的类方法。这样可以将所有内容保持在一个类中,这意味着您不必担心导入任何内容。

答案 2 :(得分:39)

我只是碰到了这个,因为我的信号与模型无关,我想我会添加我的解决方案。

我在登录/注销时记录各种数据,需要挂钩django.contrib.auth.signals

我已将信号处理程序放入signals.py文件,然后从__init__.py模块文件导入信号,因为我相信只要应用程序启动就会调用此信号(使用{ {1}}语句建议在读取设置文件之前调用它。)

print

和signals.py

# /project/__init__.py
import signals

我是Django(/ python)的新手,所以任何人都可以告诉我这是一个糟糕的主意!

答案 3 :(得分:13)

我刚刚阅读了this关于布局项目/应用程序的最佳做法的文章,并建议所有自定义调度程序信号都应放在名为signals.py的文件中。但是,这并不能完全解决您的问题,因为您仍然需要在某处导入这些问题,导入越早越好。

模型建议很好。由于您已经在signals.py文件中定义了所有内容,因此它不应超过文件顶部的一行。这与admin.py文件的布局方式类似(顶部的类定义和底部注册所有自定义管理类的代码),如果定义信号,则将它们连接到同一文件中

希望有所帮助!最终归结为你喜欢的东西。

答案 4 :(得分:7)

每个应用程序中的models.py和signals.py一直是连接信号的推荐位置,但是,在我看来,它们不是保持信号和处理程序分派的最佳解决方案。调度应该是django发明信号和处理程序的原因。

我挣扎了很长时间,最后我们找到了解决方案。

在app文件夹中创建连接器模块

所以我们有:

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中。模型和信号没有混乱。

希望它提供另一种解决方案。

答案 5 :(得分:3)

关于AppConfig的小提醒。不要忘记设置:

# yourapp/__init__.py

default_app_config = 'yourapp.apps.RockNRollConfig'

答案 6 :(得分:2)

在定义所有模型后,我将它们保存在单独的文件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 中没有任何问题,但这种方式更容易管理。

希望这会有所帮助!!