Opierając się na dokumentacji Django, którą czytałem, wydaje się, signals.py
że folder aplikacji jest dobrym miejscem do rozpoczęcia, ale problem, z którym się spotykam, polega na tym, że kiedy tworzę sygnały pre_save
i próbuję zaimportować klasę z modelu, jest to import
w moim modelu.
# 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]
Ten kod nie będzie działał, ponieważ importuję Comm_Queue
wewnątrz, signals.py
a także importuję sygnały wewnątrz models.py
.
Czy ktoś może poradzić się, jak mogę rozwiązać ten problem?
pozdrowienia
django
django-signals
Mo J. Mughrabi
źródło
źródło
Odpowiedzi:
Oryginalna odpowiedź, dla Django <1.7:
Możesz zarejestrować sygnały, importując
signals.py
je do__init__.py
pliku aplikacji :# __init__.py import signals
To pozwoli na import
models.py
zsignals.py
bez okrągłych błędów importu.Jednym z problemów związanych z tym podejściem jest to, że zniekształca wyniki pokrycia, jeśli używasz pokrycia.
Powiązana dyskusja
Edycja: dla Django> = 1.7:
Od czasu wprowadzenia AppConfig zalecanym sposobem importowania sygnałów jest jego
init()
funkcja. Zobacz odpowiedź Erica Marcosa, aby uzyskać więcej informacji.źródło
AppRegistryNotReady("Apps aren't loaded yet.")
Jeśli używasz Django <= 1.6, polecam rozwiązanie Kamagatos: po prostu zaimportuj sygnały na końcu modułu modeli.
W przypadku przyszłych wersji Django (> = 1.7) zalecanym sposobem jest zaimportowanie modułu sygnałów do funkcji config ready () aplikacji :
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'
źródło
doesn't declare an explicit app_label
..Aby rozwiązać problem, wystarczy zaimportować pliki signal.py po definicji modelu. To wszystko.
źródło
Umieszczam również sygnały w pliku signal.py, a także mam ten fragment kodu, który ładuje wszystkie sygnały:
# 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)))
To jest dla projektu, nie jestem pewien, czy działa na poziomie aplikacji.
źródło
W starych wersjach Django byłoby dobrze umieścić sygnały na
__init__.py
lub może wmodels.py
(chociaż na koniec modele będą zdecydowanie za duże jak na mój gust).W przypadku Django 1.9 lepiej jest, jak sądzę, umieścić sygnały w
signals.py
pliku i zaimportować je z plikiemapps.py
, gdzie zostaną załadowane po załadowaniu modelu.apps.py:
from django.apps import AppConfig class PollsConfig(AppConfig): name = 'polls' def ready(self): from . import signals # NOQA
Możesz również podzielić swoje sygnały na
signals.py
ihandlers.py
w innym folderze w swoim modelu, również o nazwiesignals
, ale dla mnie to tylko kwestia inżynierii. Spójrz na Umieszczanie sygnałówźródło
Domyślam się, że robisz to, aby Twoje sygnały były rejestrowane, aby gdzieś je znaleźć. Po prostu umieszczam moje sygnały normalnie w pliku models.py.
źródło
Ma to zastosowanie tylko wtedy, gdy masz sygnały w oddzielnym
signals.py
plikuCałkowicie zgadzam się z odpowiedzią @EricMarcos, ale należy stwierdzić, że dokumentacja django wyraźnie radzi, aby nie używać zmiennej default_app_config (chociaż nie jest to zła). W przypadku aktualnych wersji poprawnym sposobem byłoby:
my_app / apps.py
from django.apps import AppConfig class MyAppConfig(AppConfig): name = 'my_app' def ready(self): import my_app.signals
settings.py
(Upewnij się, że nie masz tylko nazwy aplikacji w zainstalowanych aplikacjach, ale zamiast tego względną ścieżkę do konfiguracji aplikacji)
INSTALLED_APPS = [ 'my_app.apps.MyAppConfig', # ... ]
źródło
Alternatywą jest zaimportowanie funkcji zwrotnych z
signals.py
i połączenie ich wmodels.py
:sygnały.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: Importowanie
YourModel
wsignals.py
stworzy rekurencji; użyjsender
zamiast tego.Ps2: ponowne zapisanie instancji w funkcji zwrotnej spowoduje utworzenie rekursji. Możesz utworzyć argument kontrolny w
.save
metodzie, aby ją kontrolować.źródło