95

私が読んでいた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()

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

Comm_Queue内部signals.pyをインポートし、内部の信号もインポートするため、このコードは実行されませんmodels.py

この問題をどのように克服できるかについて誰かがアドバイスできますか?

よろしく

4

8 に答える 8

217

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

my_app/__init__.py

default_app_config = 'my_app.apps.MyAppConfig'
于 2014-02-06T19:21:55.363 に答える
68

元の回答、Django <1.7の場合:

signals.pyアプリの__init__.pyファイルにインポートすることで、シグナルを登録できます。

# __init__.py
import signals

これにより、循環インポートエラーなしでmodels.pyからインポートできるようになります。signals.py

このアプローチの問題の1つは、coverage.pyを使用している場合、カバレッジ結果が台無しになることです。

関連する議論

編集:Djangoの場合> = 1.7:

AppConfigが導入されて以来、シグナルをインポートするための推奨される方法はそのinit()機能にあります。詳細について は、 EricMarcosの回答を参照してください。

于 2013-01-07T08:28:18.790 に答える
27

問題を解決するには、モデル定義の後にsignals.pyをインポートする必要があります。それで全部です。

于 2012-03-24T12:44:09.123 に答える
6

また、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)))

これはプロジェクト用です。アプリレベルで機能するかどうかはわかりません。

于 2012-03-08T09:28:30.777 に答える
6

古いDjangoバージョンでは、信号を__init__.pyまたはに配置するのが適切ですmodels.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.py信号をhandlers.pyモデル内の別のフォルダーに分割することもできますsignalsが、私にとってはそれはエンジニアリングを超えています。信号の配置を見てください

于 2017-01-12T13:26:28.710 に答える
4

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

settings.py

(インストールされているアプリにアプリ名だけでなく、AppConfigへの相対パスがあることを確認してください)

INSTALLED_APPS = [
    'my_app.apps.MyAppConfig',
    # ...
]
于 2019-05-14T16:31:04.903 に答える
3

信号が登録され、どこかで見つかるようにそうしていると思います。通常、信号をmodels.pyファイルに正しく配置します。

于 2011-08-18T23:38:37.723 に答える
1

別の方法は、コールバック関数をからインポートし、signals.pyそれらを接続することですmodels.py

signals.py

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

model.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)

追伸:インポートYourModelするsignals.pyと再帰が作成されます。sender代わりに、を使用してください。

追伸:インスタンスをコールバック関数に再度保存すると、再帰が作成されます。あなたはそれを制御するためにメソッドで制御引数を作ることができます.save

于 2012-03-21T18:57:59.160 に答える