Основываясь на документации 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
.
Может ли кто-нибудь посоветовать, как я могу решить эту проблему?
С уважением
django
django-signals
Мо Дж. Муграби
источник
источник
Ответы:
Оригинальный ответ для Django <1.7:
Вы можете зарегистрировать сигналы, импортировав
signals.py
в__init__.py
файл приложения :# __init__.py import signals
Это позволит импортировать
models.py
изsignals.py
без круговых ошибок импорта.Одна из проблем с этим подходом состоит в том, что он портит результаты покрытия, если вы используете extension.py.
Связанное обсуждение
Изменить: для Django> = 1.7:
С момента появления AppConfig рекомендуемый способ импорта сигналов - это его
init()
функция. См. Ответ Эрика Маркоса для получения более подробной информации.источник
AppRegistryNotReady("Apps aren't loaded yet.")
Если вы используете 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'
источник
doesn't declare an explicit app_label
..Чтобы решить вашу проблему, вам просто нужно импортировать signal.py после определения вашей модели. Вот и все.
источник
Я также помещаю сигналы в файл signal.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.py
иhandlers.py
в другой папке сsignals
таким же именем , но для меня это просто инженерия. Взгляните на Размещение сигналовисточник
Я предполагаю, что вы делаете это для того, чтобы ваши сигналы были зарегистрированы и где-то были найдены. Обычно я просто помещаю свои сигналы прямо в файл models.py.
источник
Это применимо только в том случае, если у вас есть ваши сигналы в отдельном
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', # ... ]
источник
Альтернативой является импорт функций обратного вызова из
signals.py
и подключение их вmodels.py
:signal.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)
Ps: Импорт
YourModel
вsignals.py
создаст рекурсию; используйтеsender
вместо этого.PS2: повторное сохранение экземпляра в функции обратного вызова создаст рекурсию. Вы можете сделать контрольный аргумент в
.save
методе, чтобы управлять им.источник