我刚开始在django项目中实现信号侦听器。虽然我明白它们是什么以及如何使用它们。我很难搞清楚应该放在哪里。来自django网站的文档可以这样说:
你可以把信号处理和 注册码随时随地。 但是,您需要确保这一点 它所在的模块很早就被导入了 因此,信号处理得到 在任何信号需要之前注册 被发送。这使你的应用程序 models.py是个好地方 注册信号处理程序。
虽然这是一个很好的建议,但在我的models.py中使用非模型类或方法只会让我误解错误。
那么,存储和注册信号处理程序的最佳实践/规则是什么?
答案 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 中没有任何问题,但这种方式更容易管理。
希望这会有所帮助!!