信号处理程序应该位于 django 项目中的什么位置?

发布于 2024-08-30 18:27:39 字数 490 浏览 8 评论 0原文

我刚刚开始在 django 项目中实现信号监听器。虽然我了解它们是什么以及如何使用它们。我很难弄清楚应该把它们放在哪里。 django 站点的文档是这样说的:

此代码应该放在哪里?< /p>

您可以将信号处理和 注册码可以放在任何你喜欢的地方。 但是,您需要确保 它所在的模块会提前导入 以便信号处理得到 在任何信号需要之前注册 被发送。这使得您的应用程序 models.py 是一个放置的好地方 信号处理程序的注册。

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

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

I have just started implementing signal listeners in a django project. While I understand what they are and how to use them. I am having a hard time figuring out where I should put them. The documentation from the django site has this to say:

Where should this code live?

You can put signal handling and
registration code anywhere you like.
However, you'll need to make sure that
the module it's in gets imported early
on so that the signal handling gets
registered before any signals need to
be sent. This makes your app's
models.py a good place to put
registration of signal handlers.

While its a good suggestion, having non model classes or methods in my models.py just rubs me the wrong way.

So then, what is the best practice/rule for storing and registering signal handlers?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

素衣风尘叹 2024-09-06 18:27:39

这是在 Django 1.7 时添加到文档中的被释放:

严格来说,信号处理和注册代码可以驻留在您喜欢的任何地方,但建议避免使用应用程序的根模块及其模型模块,以最大程度地减少导入代码的副作用。

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

Django 1.7中的变化:由于之前版本的Django中不存在ready(),信号注册通常发生在models模块中。

最佳实践是在信号子模块的 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

注册信号处理程序的最佳位置是在使用 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。您的应用程序的。请参阅查看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。将信号与处理程序分开可以使事情保持干净。

Django 1.6 说明

如果您仍然停留在 Django 1.6 或更低版本上,那么您可以做同样的事情(在 yourapp/signals/handlers.py 中定义处理程序),而不是使用 AppConfig ,您可以通过应用程序的 _init_.py 加载处理程序,例如:

yourapp/_init_.py

import signals

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

This was added to the documentation when Django 1.7 was released:

Strictly speaking, signal handling and registration code can live anywhere you like, although it’s recommended to avoid the application’s root module and its models module to minimize side-effects of importing code.

In practice, signal handlers are usually defined in a signals submodule of the application they relate to. Signal receivers are connected in the ready() method of your application configuration class. If you’re using the receiver() decorator, simply import the signals submodule inside ready().

Changed in Django 1.7: Since ready() didn’t exist in previous versions of Django, signal registration usually happened in the models module.

Best practice is to define your handlers in handlers.py in a signals submodule, e.g. a file that looks like:

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

The best place to register your signal handler is then in the AppConfig of the app that defines it, using the ready() method. This will look like this:

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

Make sure you're loading your AppConfig by specifying it either directly in your settings.py's INSTALLED_APPS, or in the __init__ of your app. See see the ready() documentation for more information.

Note: If you're providing signals for other apps to listen too as well, put them in the __init__ in your signals module, e.g. a file that looks like:

yourapp/signals/_init_.py

import django.dispatch

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

Another app can then listen to your signal by importing and registering it, e.g. from yourapp.signals import task_generate_pre_save. Separating your signals from your handlers keeps things clean.

Instructions for Django 1.6:

If you're still stuck on Django 1.6 or lower, then you'd do the same thing (define your handlers in yourapp/signals/handlers.py) but rather than using AppConfig, you would load the handlers via the _init_.py of your app, e.g. something like:

yourapp/_init_.py

import signals

This isn't as nice as using the ready() method because it often causes circular import issues.

抱猫软卧 2024-09-06 18:27:39

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

I actually like to make them classmethods of the model itself. That keeps everything within one class, and means you don't have to worry about importing anything.

Saygoodbye 2024-09-06 18:27: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(/python)非常陌生,所以我对任何告诉我的人持开放态度我认为这是一个糟糕的主意!

I've only just come across this, and as my signals are not model-related I thought I'd add my solution.

I am logging various data around log in / log out, and needed to hook into django.contrib.auth.signals.

I have put the signal handlers into a signals.py file, and then imported signals from the __init__.py module file, as I believe this is called as soon as the app starts up (testing with a print statement suggests that it's called even before the settings file is read.)

# /project/__init__.py
import signals

and in 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)

I'm pretty new to Django (/python) so am open to anyone telling me that this is a terrible idea!

感性 2024-09-06 18:27:39

我最近刚刚读过这个 关于布局项目/应用程序的最佳实践的文章,它建议所有自定义调度程序信号都应放入名为 signals.py 的文件中。但是,这并不能完全解决您的问题,因为您仍然需要将它们导入到某个地方,并且越早导入越好。

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

希望有帮助!最终取决于您的喜好。

I just recently read this article about best practices when it comes to lay out your projects/applications, and it suggests that all your custom dispatcher signals should go in a file called signals.py. However, that doesn't fully solve your problem, since you still need to import these somewhere, and the earlier they get imported the better.

The model suggestion is a good one. Since you already defined everything in your signals.py file, it shouldn't take more than a line at the top of the the file. This is similar to the way the admin.py file is laid out (with class definitions at the top and the code for registering all the custom admin classes at the bottom), if you define your signals then connect them in the same file.

Hope that helps! Ultimately it comes down to what you prefer.

悲凉≈ 2024-09-06 18:27:39

每个应用程序中的 models.py 和 Signals.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

Everything did here。

这样,我们就可以将信号放入signals.py中,并将所有处理程序放入connectors.py中。模型和信号不会混乱。

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

models.py and signals.py in each app have been the recommended places to connect signals, however, they are not the best solution, in my opinion, to keep signals and handlers dispatched. Dispatching should be the reason signals and handlers invented in django.

I was struggling for long time, and finally we figured out the solution.

create a connector module in app folder

so we have:

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

in app/connectors.py, we defined signal handlers and connect them. An example is provided:

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)

then in models.py, we add the following line in the end of the file:

from app import connector

Everything done here.

In this way, we can put signals in signals.py, and all the handlers in connectors.py. No mess in models and signals.

Hope it provides another solution.

一萌ing 2024-09-06 18:27:39

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

# yourapp/__init__.py

default_app_config = 'yourapp.apps.RockNRollConfig'

Small reminder about AppConfig. Don't forget to set:

# yourapp/__init__.py

default_app_config = 'yourapp.apps.RockNRollConfig'
污味仙女 2024-09-06 18:27:39

我将它们保存在一个单独的文件 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 中没有任何问题,但这种方式更易于管理。

希望这有帮助!

I keep them in a separate file signals.py , In models.py after all models are defined. I import them and connect models to signals.

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)

This provides me logical separation, of course there is nothing wrong on keeping them in models.py , But it is more manageable this way.

Hope this helps!!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文