Según la documentación de Django que estaba leyendo, parece que signals.py
la carpeta de la aplicación es un buen lugar para comenzar, pero el problema al que me enfrento es que cuando creo señales para pre_save
e intento importar la clase desde el modelo, entra en conflicto con la import
en mi modelo.
# 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]
Este código no se ejecutará porque importo Comm_Queue
dentro signals.py
y también importo las señales dentro models.py
.
¿Alguien puede darme un consejo sobre cómo podría superar este problema?
Saludos
django
django-signals
Mo J. Mughrabi
fuente
fuente
Respuestas:
Respuesta original, para Django <1.7:
Puede registrar las señales importando
signals.py
en el__init__.py
archivo de la aplicación :# __init__.py import signals
Esto permitirá importar
models.py
desdesignals.py
sin errores de importación circulares.Un problema con este enfoque es que estropea los resultados de la cobertura si está utilizando el archivo cover.py.
Discusión relacionada
Editar: para Django> = 1.7:
Desde que se introdujo AppConfig, la forma recomendada de importar señales es en su
init()
función. Consulte la respuesta de Eric Marcos para obtener más detalles.fuente
AppRegistryNotReady("Apps aren't loaded yet.")
Si está utilizando Django <= 1.6, recomendaría la solución Kamagatos: simplemente importe sus señales al final de su módulo de modelos.
Para futuras versiones de Django (> = 1.7), la forma recomendada es importar su módulo de señales en la función config ready () de su aplicación :
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'
fuente
doesn't declare an explicit app_label
..Para resolver su problema, solo tiene que importar señales.py después de la definición de su modelo. Eso es todo.
fuente
También puse señales en el archivo señales.py y también tengo este fragmento de código que carga todas las señales:
# 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)))
Esto es para el proyecto, no estoy seguro de si funciona a nivel de aplicación.
fuente
En versiones antiguas de Django estaría bien poner las señales en
__init__.py
o tal vez enmodels.py
(aunque al final los modelos serán demasiado grandes para mi gusto).Con Django 1.9, creo que es mejor colocar las señales en un
signals.py
archivo e importarlas con elapps.py
, donde se cargarán después de cargar el modelo.apps.py:
from django.apps import AppConfig class PollsConfig(AppConfig): name = 'polls' def ready(self): from . import signals # NOQA
También puede dividir sus señales de
signals.py
yhandlers.py
en otra carpeta dentro de su modelo llamadosignals
así, pero para mí eso es un poco más de la ingeniería. Eche un vistazo a Colocación de señalesfuente
Supongo que lo está haciendo para que sus señales estén registradas, de modo que se encuentren en alguna parte. Solo pongo mis señales en un archivo models.py normalmente.
fuente
Esto solo se aplica si tiene sus señales en un
signals.py
archivo separadoEstoy completamente de acuerdo con la respuesta de @EricMarcos, pero debe indicarse que los documentos de django recomiendan explícitamente no usar la variable default_app_config (aunque no está mal). Para las versiones actuales, la forma correcta sería:
my_app / apps.py
from django.apps import AppConfig class MyAppConfig(AppConfig): name = 'my_app' def ready(self): import my_app.signals
settings.py
(Asegúrese de no tener solo el nombre de su aplicación en las aplicaciones instaladas, sino la ruta relativa a su AppConfig)
INSTALLED_APPS = [ 'my_app.apps.MyAppConfig', # ... ]
fuente
Una alternativa es importar las funciones de devolución de llamada
signals.py
y conectarlas enmodels.py
:señales.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: La importación
YourModel
ensignals.py
crearán una recursividad; utilizarsender
, en su lugar.Ps2: Guardar la instancia nuevamente en la función de devolución de llamada creará una recursividad. Puede hacer un argumento de control en el
.save
método para controlarlo.fuente