Importing models in signals cause django deprecation warnings app_label - python

This is my code in my signals.py
from .models import Entry
#receiver(pre_save, sender=Entry)
def do_stuff(sender, instance, *args, **kwargs):
pass
Now this questions is related
Django 1.9 deprecation warnings app_label
But I am not able to figure out why I need to create extra class for that.
Warning:
Model class app.models.Entry doesn't declare an explicit app_label and either isn't in
an application in INSTALLED_APPS or else was imported before its application was loaded.
This will no longer be supported in Django 1.9.
If I just empty my signals file then there is no warning.
The issue is using .models in signals as mentioned in that question

This is mostly likely because your application is not in the INSTALLED_APPS within your settings.py

I also got this error, what I found the error is in model import before it exist.
I used this to import model and it works for me
from django.apps import apps
model_obj = apps.get_model('app_name', 'model_name')
model_obj.objects.get() ...etc

Related

Django signals not called when app is registered using package name but works with app config class

I was experiencing a problem where my signals were not getting called. I have an app called users and in it I have a model for Profile that extends the django User model and when a user object is saved, I need to create a corresponding profile for it for that I added a signals.py module in the users app, here's my signals file
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, created, **kwargs):
instance.profile.save()
And inside my settings.py INSTALLED_APPS I added my app like this
INSTALLED_APPS = [
# other apps
'users',
]
And my users/apps.py looks like this
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
def ready(self):
import users.signals
After registration, the user object was getting created but no corresponding profile. I even put some debug statements in the signal receivers just to confirm my receivers were not getting called and yes the receivers were never getting called.
I couldn't find a solution to this as all answers I found on SO showed similar configurations that worked. Out of curiosity I decided to register the users app using config class and not the module name and changed my settings INSTALLED_APP to look like this
INSTALLED_APPS = [
# other apps
'users.apps.UsersConfig',
]
After doing that everything was working. On registration a new user, a profile was been created from within my signal receiver.
Now I don't understand what difference doing that makes. Everything(migrations, templates, etc) else was working fine with the previous configuration. Why did I have to change it for my signal receivers to work?
Prior to the Django 3.2 version, Django was only checking default_app_config in your applications __init__.py file to determine which application configuration class should be used by default when you've not provided it explicitly in your INSTALLED_APPS. If you didn't specify one there, it will create a new, blank one for you and use that.
On 3.2 release this has changed and now, if there is AppConfig class in your apps.py file with default = True set, this one will be used by default or if your application defines only one AppConfig in the apps.py file and it doesn't have the default = True specified, this one will be used.
You can read more about the new behavior in the changelog and for the previous behavior, you can check docs of the 3.1 version
To fix your problem, you can either define default_app_config in your application or upgrade the Django version to 3.2 (given you have only one AppConfig defined or you've marked one with default = True), whichever is more relevant to your case.

Use signals in Django 1.9

In Django 1.8, I was able to do the following with my signals, and all was well:
__init__.py:
from .signals import *
signals.py:
#receiver(pre_save, sender=Comment)
def process_hashtags(sender, instance, **kwargs):
html = []
for word in instance.hashtag_field.value_to_string(instance).split():
if word.startswith('#'):
word = render_to_string('hashtags/_link.html',
{'hashtag': word.lower()[1:]})
html.append(word)
instance.hashtag_enabled_text = ' '.join(html)
In Django 1.9, I get this error: django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
I know it's coming from the __init__.py, but does anyone know a workaround for this? I'm assuming maybe putting it in the models? If so, could someone please show me how to do that?
models.py:
class Comment(HashtagMixin, TimeStampedModel):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
text = models.TextField(max_length=240)
hashtag_enabled_text = models.TextField(blank=True)
hashtag_text_field = 'text'
objects = CommentManager()
class Meta:
app_label = 'comments'
def __unicode__(self):
return self.text
Thank you in advance!
From the release notes:
All models need to be defined inside an installed application or declare an explicit app_label. Furthermore, it isn’t possible to import them before their application is loaded. In particular, it isn’t possible to import models inside the root package of an application.
By importing your signals in __init__.py, you're indirectly importing your models in the root package of your application. One option to avoid this is to change the sender to a string:
#receiver(pre_save, sender='<appname>.Comment')
def process_hashtags(sender, instance, **kwargs):
...
The recommended way to connect signals that use #receiver decorator in 1.9 is to create an application configuration, and import the signals module in AppConfig.ready().

in django 1.8, how to set sender for post_migrate and post_syncdb signal receiver when a custom user model is set?

Following is my code in the signals.py file placed in the package where the auth model is defined.
#receiver(post_migrate, sender=settings.AUTH_USER_MODEL)
def define_groups(sender, **kwargs):
# Create groups
Group.objects.get_or_create(name='Promoter')
Group.objects.get_or_create(name='Client')
Group.objects.get_or_create(name='Superuser')
Group.objects.get_or_create(name='Staff')
The documentation (https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#referencing-the-user-model) states that it should be set as
sender=settings.AUTH_USER_MODEL
while this only works for post_save as mentioned in the documentation example.
I've already tried get_user_model() and also directly using the my_custom_user.models.
get_user_model() returns an error, while setting models as sender works just fine, as -
from . import models
#receiver(post_syncdb, sender=models)
def define_groups(sender, **kwargs):
# Create groups
Group.objects.get_or_create(name='Promoter')
Group.objects.get_or_create(name='Client')
Group.objects.get_or_create(name='Superuser')
Group.objects.get_or_create(name='Staff')
But according to documentation this is not the right way to refer a custom user model and is just an ugly workaround.
Would someone please be able to help me with a solution so i can add these Groups with the first migration of user model.
Thank You
EDIT : using get_user_model() returns the following error -
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
The sender for the post_migrate method is never a model (custom or otherwise), it is the AppConfig instance for the app which was installed.
The docs give the following example for connecting your signal handler in the ready method.
from django.apps import AppConfig
from django.db.models.signals import post_migrate
def my_callback(sender, **kwargs):
# Your specific logic here
pass
class MyAppConfig(AppConfig):
...
def ready(self):
post_migrate.connect(my_callback, sender=self)
Similarly, the sender for post_sync_db signal (note the signal is deprecated) is the module containing the models which were installed.

How can i get all models in django 1.8

I am using this code in my admin.py
from django.db.models import get_models, get_app
for model in get_models(get_app('myapp')):
admin.site.register(model)
But i get warning that get_models is deprecated
How can i do that in django 1.8
This should work,
from django.apps import apps
apps.get_models()
The get_models method returns a list of all installed models. You can also pass three keyword arguments include_auto_created, include_deferred and include_swapped.
If you want to get the models for a specific app, you can do something like this.
from django.apps import apps
myapp = apps.get_app_config('myapp')
myapp.models
This will return an OrderedDict instance of the models for that app.

When is django.conf.global_settings loaded?

I created following custom user model by using "AbstractUser" model.
from django.conf.global_settings import AUTH_USER_MODEL
MyCustomUser(AbstractUser):
regions = models.ManyToManyField(to='SomeModel')
class Meta:
app_label = 'myapp'
MyObject(models.Model):
owner = models.ForeignKey(to=AUTH_USER_MODEL)
And I set AUTH_USER_MODEL to settings/base.py (I separated setting file each environment. e.x: settings/base.py, settings/development.py).
AUTH_USER_MODEL = 'myapp.MyCustomUser'
When I executed python manage.py syncdb, my console window has flared up by Django!
myapp.MyObject: 'owner' defines a relation with the model 'auth.User', which has been swapped out. Update the relation to point at settings.AUTH_USER_MODEL.
So, I had two questions.
Is the problem is that I separated settings.py each environment.
Does from django.global_settings import AUTH_USER_MODEL import myproject.settings?
And I resolved from myproject.settings.base import AUTH_USER_MODEL in this time.
global_settings is, as the name implies, the global default settings supplied by Django. So of course the default is 'auth.User'.
Since you override it in your own settings, you should import that instead. But as the documentation says, the way to import the current settings is always from django.conf import settings, rather than explicitly importing a settings file in your project.
Also note though that rather than using the settings at all here - which could lead to some dependency issues on startup - you should be using get_user_model() from django.contrib.auth, as explained in the documentation.

Categories