私が読んでいたDjangoのドキュメントに基づいて、アプリフォルダーの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]
Comm_Queue
内にsignals.py
をインポートし、models.py
内に信号もインポートするため、このコードは実行されません。
誰も私がこの問題を克服する方法についてアドバイスできますか?
よろしく
アプリの_signals.py
_ファイルに___init__.py
_をインポートして、信号を登録できます。
_# __init__.py
import signals
_
これにより、循環インポートエラーなしで_models.py
_から_signals.py
_をインポートできます。
このアプローチの1つの問題は、coverage.pyを使用している場合、カバレッジの結果が台無しになることです。
AppConfigが導入されて以来、信号をインポートする推奨される方法はinit()
関数にあります。詳細については、 Eric Marcosの回答 を参照してください。
Django <= 1.6を使用している場合、Kamagatosソリューションをお勧めします。モデルモジュールの最後に信号をインポートするだけです。
Django(> = 1.7)の将来のバージョンでは、 推奨 方法は、アプリの設定でシグナルモジュールをインポートすることです 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'
問題を解決するには、モデル定義の後にsignals.pyをインポートするだけです。それで全部です。
また、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)))
これはプロジェクト用であり、アプリレベルで機能するかどうかはわかりません。
古い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
という名前のモデル内の別のフォルダー内のsignals.py
とhandlers.py
で信号を分割することもできますが、私にとっては、これはエンジニアリングを超えています。 信号の配置 をご覧ください
私はあなたがそうしていると推測しているので、あなたの信号は登録され、どこかで見つかるようになります。私は通常、models.pyファイルに信号を入れます。
別の方法は、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)
追伸:signals.py
にYourModel
をインポートすると、再帰が作成されます。代わりにsender
を使用してください。
Ps2:コールバック関数でインスタンスを再度保存すると、再帰が作成されます。 .save
メソッドで制御引数を作成して制御できます。
これは、別の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',
# ...
]