在 django 项目中,信号处理程序应该驻留在哪里?

我刚刚开始在一个 django 项目中实现信号侦听器。而我知道它们是什么,以及如何使用它们。我很难决定把它们放在哪里。来自 django 站点的文档说:

这个代码应该放在哪里?

你可以把信号处理和 注册码随便你选。 但是,你需要确保这一点 它所在的模块被提前导入 这样信号处理就可以 在任何讯号需要前登记 这使得你的应用程序 模特们,找个好地方放 信号处理程序的注册。

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

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

42487 次浏览

我最近读了一篇关于最佳实践的 这个文章,它建议所有自定义调度程序信号都应该放在一个名为 signals.py的文件中。但是,这并不能完全解决您的问题,因为您仍然需要在某个地方导入这些文件,并且越早导入越好。

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

希望这能有所帮助! 最终还是取决于你喜欢什么。

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

我刚刚遇到这个问题,由于我的信号与模型无关,我想我应该添加我的解决方案。

我正在登录/退出时记录各种数据,需要连接到 django.contrib.auth.signals

我已经把信号处理程序放入一个 signals.py文件,然后从 __init__.py模块文件导入信号,因为我相信应用程序一启动就会调用这个函数(使用 print语句测试表明,它甚至在读取设置文件之前就被调用了)

# /project/__init__.py
import signals

还有信号

# /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 (/python)相当陌生,所以我愿意接受任何人告诉我这是一个糟糕的主意!

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

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

这是在 姜戈1.7发布时加入到 文件中的:

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

在实践中,信号处理程序通常定义在与它们相关的应用程序的信号子模块中。信号接收器在应用程序配置类的 ready ()方法中连接。如果您正在使用接收器()修饰符,那么只需导入 ready ()中的信号子模块。

在 Django 1.7中更改: 由于 ready ()在以前的 Django 版本中不存在,信号注册通常发生在 model 模块中。

最佳实践是在 handlers.py 中定义您的处理程序,例如,一个文件看起来像:

Yourapp/Signals/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

通过直接在 setings.py 的 INSTALLED _ APPS 或应用程序的 __init__中指定 AppConfig,确保正在加载 AppConfig。有关更多信息,请参见 查看 ready ()文档

注意: 如果你也为其他应用程序提供监听信号,把它们放在信号模块的 __init__中,例如:

Yourapp/Signals/_ Init _.py

import django.dispatch


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

另一个应用程序可以通过导入和注册来监听你的信号,例如 from yourapp.signals import task_generate_pre_save。把你的信号和你的联络人分开可以保持干净。

姜戈1.6使用说明:

如果你仍然停留在 Django 1.6或更低版本上,那么你会做同样的事情(在你的应用程序/Signals/handlers.py 中定义你的处理程序) ,但不是使用 AppConfig,你会通过应用程序的 _ Init _.py 加载处理程序,例如:

Yourapp/_ Init _.py

import signals

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

我保持他们在一个单独的文件 signals.py,在 models.py后,所有的模型被定义。我导入它们,把模型和信号连接起来。

信号 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中保持它们没有什么错误,但这样更容易管理。

希望这个能帮上忙!

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

# yourapp/__init__.py


default_app_config = 'yourapp.apps.RockNRollConfig'