保持我的signals.py文件在Django项目中的正确位置

Mo *_*abi 76 django django-signals

基于我正在阅读的Django文档,似乎signals.py在app文件夹中是一个很好的开始,但我面临的问题是,当我创建信号时pre_save,我尝试从模型中导入类,它与import在我的模型中.

# models.py

from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import gettext as _
from signals import *

class Comm_Queue(CommunicatorAbstract):
    queue_statuses = (
        ('P', _('Pending')),
        ('S', _('Sent')),
        ('E', _('Error')),
        ('R', _('Rejected')),
    )
    status          = models.CharField(max_length=10, db_index=True, default='P')
    is_html         = models.BooleanField(default=False)
    language        = models.CharField(max_length=6, choices=settings.LANGUAGES)
    sender_email    = models.EmailField()
    recipient_email = models.EmailField()
    subject         = models.CharField(max_length=100)
    content         = models.TextField()
Run Code Online (Sandbox Code Playgroud)
# signals.py

from django.conf import settings
from django.db.models.signals import pre_save
from django.dispatch import receiver
from models import Comm_Queue

@receiver(pre_save, sender=Comm_Queue)
def get_sender_email_from_settings(sender, **kwargs):
    obj=kwargs['instance']
    if not obj.sender_email:
        obj.sender_email='%s' % settings.ADMINS[0][1]
Run Code Online (Sandbox Code Playgroud)

此代码将无法运行,因为我导入Comm_Queue内部signals.py,我也导入内部信号models.py.

任何人都可以就如何解决这个问题提出建议吗?

问候

Eri*_*cos 177

如果您使用的是Django <= 1.6,我建议使用Kamagatos解决方案:只需在模型模块的末尾导入信号.

对于Django的未来版本(> = 1.7),推荐的方法是在应用程序的config ready()函数中导入信号模块:

my_app/apps.py

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'my_app'

    def ready(self):
        import my_app.signals
Run Code Online (Sandbox Code Playgroud)

my_app/__init__.py

default_app_config = 'my_app.apps.MyAppConfig'
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案!使用uwsgi进行部署时,上面接受的答案会引发错误 (12认同)
  • 他们还在1.7文档中提到有时可以多次调用,因此为了避免重复信号,请在信号连接器调用中附加唯一标识符:request_finished.connect(my_callback,dispatch_uid ="my_unique_identifier")其中dispatch_uid通常是一个字符串但可以是任何可清洗的物体.https://docs.djangoproject.com/en/1.7/topics/signals/#preventing-duplicate-signals (5认同)
  • 嗯,django 2 对我不起作用。如果我直接导​​入模型准备就绪 - 一切正常。如果我在信号中导入模型并在准备好导入信号时,我会收到一个错误“未声明显式 app_label”.. (2认同)

ypr*_*rez 61

对于Django <1.7的原始答案:

您可以通过导入signals.py应用程序的__init__.py文件来注册信号:

# __init__.py
import signals
Run Code Online (Sandbox Code Playgroud)

这将允许models.pysignals.py没有循环导入错误导入.

这种方法的一个问题是,如果你使用的是coverage.py,它会混淆覆盖率结果.

相关讨论

编辑:对于Django> = 1.7:

自AppConfig推出以来,推荐的导入信号的方法就在于它的init()功能.有关详细信息,请参阅 Eric Marcos的回答.

  • 使用Django 1.9中的信号,使用下面的方法(由django推荐).这个方法不起作用,给出了'AppRegistryNotReady("尚未加载应用程序.")` (6认同)

Kam*_*tos 25

要解决您的问题,您只需在模型定义后导入signals.py.就这样.

  • 到目前为止,这是最简单的,我不知道如果没有循环依赖,这将有效.谢谢! (2认同)
  • 辉煌.喜欢这个比我的回答更好.虽然我真的不明白为什么它不会导致循环导入...... (2认同)

Xen*_*mar 6

仅当您的信号位于单独的signals.py文件中时,这才适用

完全同意@EricMarcos的答案,但应该指出的是,django文档明确建议不要使用default_app_config变量(尽管它没有错)。对于当前版本,正确的方法是:

my_app/apps.py

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'my_app'

    def ready(self):
        import my_app.signals
Run Code Online (Sandbox Code Playgroud)

设置.py

(确保您在已安装的应用程序中不仅有您的应用程序名称,还有 AppConfig 的相对路径)

INSTALLED_APPS = [
    'my_app.apps.MyAppConfig',
    # ...
]
Run Code Online (Sandbox Code Playgroud)


ais*_*baa 5

我还将信号放在signals.py文件中,并且还有这个加载所有信号的代码片段:

# import this in url.py file !

import logging

from importlib import import_module

from django.conf import settings

logger = logging.getLogger(__name__)

signal_modules = {}

for app in settings.INSTALLED_APPS:
    signals_module = '%s.signals' % app
    try:
        logger.debug('loading "%s" ..' % signals_module)
        signal_modules[app] = import_module(signals_module)
    except ImportError as e:
        logger.warning(
            'failed to import "%s", reason: %s' % (signals_module, str(e)))
Run Code Online (Sandbox Code Playgroud)

这是针对项目的,我不确定它是否适用于应用程序级别.


Tys*_*dez 5

在旧的 Django 版本中,可以将信号放在__init__.py或 中models.py(尽管最终模型对我来说会很大)。

对于 Django 1.9,我认为最好将信号放在signals.py文件中并使用 导入它们,apps.py加载模型后将在其中加载它们。

应用程序.py:

from django.apps import AppConfig


class PollsConfig(AppConfig):
    name = 'polls'

    def ready(self):
        from . import signals  # NOQA
Run Code Online (Sandbox Code Playgroud)

您还可以在模型内的另一个文件夹中signals.pyhandlers.py中划分信号signals,但对我来说这只是工程设计。看一下放置信号