Jas*_*ebb 135 django signal-handling
我刚刚开始在django项目中实现信号监听器.虽然我明白它们是什么以及如何使用它们.我很难搞清楚应该放在哪里.来自django网站的文档有这样的说法:
您可以将信号处理和注册码放在任何您喜欢的地方.但是,您需要确保早期导入模块,以便在需要发送任何信号之前注册信号处理.这使您的应用程序的models.py成为放置信号处理程序注册的好地方.
虽然这是一个很好的建议,但在我的models.py中使用非模型类或方法只会让我误以为然.
那么,存储和注册信号处理程序的最佳实践/规则是什么?
Aid*_*dan 230
当Django 1.7发布时,这被添加到文档中:
严格地说,信号处理和注册代码可以在任何你喜欢的地方生活,尽管建议避免应用程序的根模块及其模型模块,以尽量减少导入代码的副作用.
实际上,信号处理程序通常在与其相关的应用程序的信号子模块中定义.信号接收器在应用程序配置类的ready()方法中连接.如果您正在使用receiver()装饰器,只需在ready()中导入信号子模块.
在Django 1.7中更改:由于在早期版本的Django中不存在ready(),因此信号注册通常发生在模型模块中.
最佳做法是在信号子模块中的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
Run Code Online (Sandbox Code Playgroud)
注册信号处理程序的最佳位置是使用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
Run Code Online (Sandbox Code Playgroud)
确保您通过直接在settings.py的INSTALLED_APPS或__init__
应用程序中指定AppConfig来加载AppConfig .有关更多信息,请参阅ready()文档.
注意:如果您为其他应用程序提供信号也要收听,请将它们放入__init__
信号模块中,例如文件看起来像:
yourapp /信号/ __ init__.py
import django.dispatch
task_generate_pre_save = django.dispatch.Signal(providing_args=["task"])
Run Code Online (Sandbox Code Playgroud)
然后,另一个应用程序可以通过导入和注册来监听您的信号,例如from yourapp.signals import task_generate_pre_save
.将信号与处理程序分开可以保持清洁.
Django 1.6的说明:
如果你仍然坚持使用Django 1.6或更低版本,那么你会做同样的事情(在yourapp/signals/handlers.py中定义你的处理程序),而不是使用AppConfig,你将通过__init__.py加载处理程序.你的应用,例如:
yourapp/__ init__.py
import signals
Run Code Online (Sandbox Code Playgroud)
这不如使用ready()方法那么好,因为它经常导致循环导入问题.
Dan*_*man 39
我实际上喜欢让它们成为模型本身的类方法.这样可以将所有内容保持在一个类中,这意味着您不必担心导入任何内容.
Hug*_*own 39
我只是碰到了这个,因为我的信号与模型无关,我想我会添加我的解决方案.
我正在登录/注销各种数据,并需要挂钩django.contrib.auth.signals
.
我已经将信号处理程序放入一个signals.py
文件中,然后从__init__.py
模块文件导入信号,因为我相信只要应用程序启动print
就会调用它(使用语句进行测试表明它甚至在读取设置文件之前就被调用了.)
# /project/__init__.py
import signals
Run Code Online (Sandbox Code Playgroud)
并在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)
Run Code Online (Sandbox Code Playgroud)
我是Django(/ python)的新手,所以任何人都可以告诉我这是一个糟糕的主意!
hor*_*ora 13
我刚刚阅读了这篇关于布局项目/应用程序的最佳实践的文章,它建议所有自定义调度程序信号都应该放在一个名为的文件中signals.py
.但是,这并不能完全解决您的问题,因为您仍然需要在某处导入这些问题,并且导入越早越好.
模型建议很好.由于您已经在signals.py
文件中定义了所有内容,因此它不应超过文件顶部的一行.这类似于admin.py
文件的布局方式(顶部的类定义和底部注册所有自定义管理类的代码),如果您定义信号,则将它们连接在同一文件中.
希望有所帮助!归根结底,它取决于你喜欢什么.
每个应用程序中的models.py和signals.py一直是连接信号的推荐位置,但是,在我看来,它们不是保持信号和处理程序发送的最佳解决方案.调度应该是django发明信号和处理程序的原因.
我挣扎了很长时间,最后我们找到了解决方案.
在app文件夹中创建连接器模块
所以我们有:
app/
__init__.py
signals.py
models.py
connectors.py
Run Code Online (Sandbox Code Playgroud)
在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)
Run Code Online (Sandbox Code Playgroud)
然后在models.py中,我们在文件的末尾添加以下行:
from app import connector
Run Code Online (Sandbox Code Playgroud)
一切都在这里完成.
通过这种方式,我们可以将信号放在signals.py中,并将所有处理程序放在connectors.py中.模型和信号没有混乱.
希望它提供另一种解决方案
关于 的小提醒AppConfig
。不要忘记设置:
# yourapp/__init__.py
default_app_config = 'yourapp.apps.RockNRollConfig'
Run Code Online (Sandbox Code Playgroud)