The right place to save the signal.py file in a Django project

Based on the Django documentation I read, it looks like signals.py in the application folder is a good place to start, but the problem I am facing is that when I create signals for pre_save and I try to import the class from model it conflicts with import in my model.

 # 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] 

This code will not run because I import Comm_Queue inside signals.py and also import signals inside models.py .

Can anyone advise how I can solve this?

respectfully

+71
django django-signals
Aug 18 2018-11-18T00:
source share
8 answers

Original answer, for Django <1.7:

You can register signals by importing signals.py into the __init__.py application file:

 # __init__.py import signals 

This will allow you to import models.py from signals.py without cyclic import errors.

One of the problems with this approach is that it will ruin the coverage results if you use cover.py.

Related discussion

Edit: For Django> = 1.7:

Since AppConfig was introduced, the recommended way to import signals is in its init() function. See Eric Marcos answer for more details.

+61
Jan 07 '13 at 8:28
source share

If you use Django <= 1.6, I would recommend Kamagatos solution: just import your signals at the end of your model module.

For future versions of Django (> = 1.7), the method is recommended to import your signal module into the configuration of your ready () application:

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' 
+168
Feb 06 '14 at 19:21
source share

To solve your problem, you just need to import signal.py after defining the model. All this.

+24
Mar 24 2018-12-12T00:
source share

I also put the signals in the signal.py file, as well as this piece of code that loads all the signals:

 # 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))) 

This is for a project, I'm not sure if it works at the application level.

+5
Mar 08 2018-12-12T00:
source share

In older versions of Django, it would be convenient to place signals on __init__.py or maybe in models.py (although at the end the models will be convenient for my taste).

With Django 1.9, it’s better to think about placing signals in the signals.py file and import them using apps.py , where they will be loaded after the model loads.

apps.py:

 from django.apps import AppConfig class PollsConfig(AppConfig): name = 'polls' def ready(self): from . import signals # NOQA 

You can also split your signals into signals.py and handlers.py in another folder in your model called signals , but for me it's just over engineering. Take a look at Signal Placement

+4
Jan 12 '17 at 13:26
source share

I assume that you are doing this so that your signals are recorded, so that they are found somewhere. I just passed my signals correctly in the models.py file.

+3
Aug 18 2018-11-18T00:
source share

An alternative is to import callback functions from signals.py and connect them to 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) 

Ps: Importing YourModel into signals.py will create a recursion; use sender instead.

Ps2: saving the instance again in the callback function will result in recursion. You can make a test argument in the .save method to control it.

+1
Mar 21 '12 at 18:57
source share

I completely agree with @EricMarcos answer, but it should be noted that django docs explicitly recommends not using the default_app_config variable (although this is not so). For current versions, the correct way would be:

my_app / apps.py

 from django.apps import AppConfig class MyAppConfig(AppConfig): name = 'my_app' def ready(self): import my_app.signals 

settings.py

(Make sure that you have not only the name of your application in the installed applications, but also the relative path to your AppConfig)

 INSTALLED_APPS = [ 'my_app.apps.MyAppConfig', # ... ] 
0
May 14 '19 at 16:31
source share



All Articles