【问题标题】:The right place to keep my signals.py file in a Django project将我的 signals.py 文件保存在 Django 项目中的正确位置
【发布时间】:2011-10-30 05:10:03
【问题描述】:

根据我正在阅读的 Django 文档,似乎 app 文件夹中的 signals.py 是一个不错的起点,但我面临的问题是,当我为 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()

# 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]

此代码不会运行,因为我在signals.py 中导入了Comm_Queue,并且我还在models.py 中导入了信号。

谁能建议我如何解决这个问题?

问候

【问题讨论】:

标签: django django-signals


【解决方案1】:

如果您使用的是 Django

对于 Django 的未来版本 (>=1.7),recommended 方法是在应用的配置 ready() 函数中导入信号模块:

my_app/apps.py

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'my_app'

    def ready(self):
        import my_app.signals

my_app/__init__.py

default_app_config = 'my_app.apps.MyAppConfig'

【讨论】:

  • 他们还在 1.7 文档中提到,有时 ready 可以被多次调用,因此为避免重复信号,请在信号连接器调用中附加一个唯一标识符: request_finished.connect(my_callback, dispatch_uid="my_unique_identifier ") 其中 dispatch_uid 通常是一个字符串,但可以是任何可散列的对象。 docs.djangoproject.com/en/1.7/topics/signals/…
  • 这应该是公认的答案!使用 uwsgi 部署时,上面接受的答案会引发错误
  • 嗯,django 2 对我不起作用。如果我直接在准备好的情况下导入模型 - 一切都很好。如果我在信号中导入模型并在准备中导入信号,我会收到错误doesn't declare an explicit app_label ..
  • @Aldarun 您可以尝试将 'my_app.apps.MyAppConfig' 放入 INSTALLED_APPS。
【解决方案2】:

原始答案,适用于 Django

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

# __init__.py
import signals

这将允许从signals.py 导入models.py 而不会出现循环导入错误。

这种方法的一个问题是,如果您使用的是coverage.py,它会弄乱覆盖结果。

Related discussion

编辑:对于 Django >= 1.7:

自从引入 AppConfig 以来,推荐的信号导入方式是在其init() 函数中。详情请见Eric Marcos' answer

【讨论】:

  • 在 Django 1.9 中使用信号,使用下面的方法(django 推荐)。这种方法不起作用给AppRegistryNotReady("Apps aren't loaded yet.")
  • Eric Marcos 他的答案应该是公认的答案:stackoverflow.com/a/21612050/3202958 since Django >= 1.7, using the app config
  • 同意。我将编辑答案以指向 Eric Marcos 对 Django 1.7+ 的回答
【解决方案3】:

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

【讨论】:

  • 这是迄今为止最简单的,我不知道这在没有循环依赖的情况下也能工作。谢谢!
  • 太棒了。喜欢这个比我的答案更好。虽然我不太明白为什么它不会导致循环导入......
  • 解决方案不适用于 Eclipse 中启用的 autopep8 插件。
【解决方案4】:

我还将信号放在了signals.py文件中,并且还有这个代码sn-p来加载所有信号:

# 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)))

这是项目,我不确定它是否适用于应用程序级别。

【讨论】:

  • 这是我最喜欢的解决方案,因为它适合其他模式(如 tasks.py)
  • 发现这个问题,如果你启动 shell,urls.py 不会被导入并且你的信号不会附加
  • 是的,我的回答有点过时了,这些天似乎 django 有 AppConfig 类。上次我使用 django 是 1.3 版。建议围绕它进行调查。
  • 我们仍然是 1.6,所以我不得不将我们所有的信号.py 移动到模型中,否则 celery 和管理命令不会被拾取
【解决方案5】:

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

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

apps.py:

from django.apps import AppConfig


class PollsConfig(AppConfig):
    name = 'polls'

    def ready(self):
        from . import signals  # NOQA

您也可以将signals.pyhandlers.py 上的信号划分到模型中名为signals 的另一个文件夹中,但对我来说,这只是过度工程。看看Placing Signals

【讨论】:

    【解决方案6】:

    这仅适用于您将信号放在单独的 signals.py 文件中

    完全同意@EricMarcos 的回答,但应该声明django docs 明确建议不要使用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
    

    settings.py

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

    INSTALLED_APPS = [
        'my_app.apps.MyAppConfig',
        # ...
    ]
    

    【讨论】:

      【解决方案7】:

      我猜你这样做是为了注册你的信号,以便在某个地方找到它们。我只是把我的信号正常地放在一个models.py文件中。

      【讨论】:

      • 是的,当我在模型文件中移动信号时,它解决了问题。但是我的 model.py 文件非常大,包含所有类、管理器和模型规则。
      • 根据我的经验,经理们更容易退出。 Managers.py ftw.
      【解决方案8】:

      另一种方法是从signals.py 导入回调函数并将它们连接到models.py

      信号.py

      def pre_save_callback_function(sender, instance, **kwargs):
          # Do stuff here
      

      模型.py

      # Your imports here
      from django.db.models.signals import pre_save
      from yourapp.signals import pre_save_callback_function
      
      class YourModel:
          # Model stuff here
      pre_save.connect(pre_save_callback_function, sender=YourModel)
      

      Ps:在signals.py中导入YourModel会产生递归;请改用sender

      Ps2:在回调函数中再次保存实例会产生递归。你可以在.save方法中做一个控制参数来控制它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-13
        • 2011-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-17
        相关资源
        最近更新 更多