D'après la documentation de Django que je lisais, il semble que signals.py
dans le dossier de l'application est un bon point de départ, mais le problème auquel je suis confronté est que lorsque je crée des signaux pour pre_save
et j'essaie d'importer la classe à partir du modèle en conflit avec le import
dans mon modèle.
# 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]
Ce code ne fonctionnera pas car j'importe Comm_Queue
à l'intérieur signals.py
et j'importe également les signaux à l'intérieur models.py
.
Quelqu'un peut-il me conseiller sur la façon de surmonter ce problème?
Cordialement
Vous pouvez enregistrer les signaux en important signals.py
Dans le fichier __init__.py
De l'application:
# __init__.py
import signals
Cela permettra d'importer models.py
À partir de signals.py
Sans erreurs d'importation circulaires.
Un problème avec cette approche est qu'elle gâche les résultats de la couverture si vous utilisez la couverture.py.
Depuis l'introduction d'AppConfig, la manière recommandée d'importer des signaux est dans sa fonction init()
. Voir réponse d'Eric Marcos pour plus de détails.
Si vous utilisez Django <= 1.6, je recommanderais la solution Kamagatos: importez simplement vos signaux à la fin de votre module de modèles.
Pour les futures versions de Django (> = 1.7), la manière recommandée consiste à importer votre module de signaux dans la configuration de votre application ready () une fonction:
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'
Pour résoudre votre problème, il vous suffit d'importer signaux.py après la définition de votre modèle. C'est tout.
J'ai également mis des signaux dans le fichier signaux.py et j'ai également cet extrait de code qui charge tous les signaux:
# 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)))
C'est pour le projet, je ne sais pas si cela fonctionne au niveau de l'application.
Dans les anciennes versions Django serait bien de placer les signaux sur le __init__.py
ou peut-être dans le models.py
(bien qu'à la fin les modèles seront bien trop grands à mon goût).
Avec Django 1.9, il vaut mieux je pense, placer les signaux sur un signals.py
fichier et importez-les avec le apps.py
, où ils seront chargés après le chargement du modèle.
apps.py:
from Django.apps import AppConfig
class PollsConfig(AppConfig):
name = 'polls'
def ready(self):
from . import signals # NOQA
Vous pouvez également diviser vos signaux sur signals.py
et handlers.py
dans un autre dossier de votre modèle nommé signals
également, mais pour moi, c'est un peu plus que l'ingénierie. Jetez un oeil à Placement des signaux
Je suppose que vous le faites pour que vos signaux soient enregistrés, afin qu'ils soient trouvés quelque part. Je mets juste mes signaux directement dans un fichier models.py normalement.
Une alternative consiste à importer les fonctions de rappel depuis signals.py
et connectez-les dans models.py
:
signaux.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: importation de YourModel
dans signals.py
créera une récursivité; utilisez plutôt sender
.
Ps2: Enregistrer à nouveau l'instance dans la fonction de rappel créera une récursivité. Vous pouvez créer un argument de contrôle dans .save
méthode pour le contrôler.
Cela ne s'applique que si vous avez vos signaux dans un fichier signals.py
Séparé
En tout à fait d'accord avec la réponse de @EricMarcos mais il faut préciser que le Django docs conseille explicitement de ne pas utiliser la variable default_app_config (bien que ce ne soit pas faux). Pour les versions actuelles, la manière correcte serait:
my_app/apps.py
from Django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'my_app'
def ready(self):
import my_app.signals
settings.py
(Assurez-vous que vous n'avez pas seulement le nom de votre application dans les applications installées, mais plutôt le chemin relatif vers votre AppConfig)
INSTALLED_APPS = [
'my_app.apps.MyAppConfig',
# ...
]