If application is referenced in `INSTALLED_APPS` by package path rather
than `AppConfig`s sublcass path, ''and'' application's author missed to
define `default_app_config`, then application's initialization will be
skipped silently. It leads to hard-to-debug bugs, especially with things
that already hard-to-debug such as scheduling asynchronous jobs with
signals.
== Details
In [https://docs.djangoproject.com/en/2.2/ref/applications/#for-
application-authors "Applications"] documentation page, it is stated that
application author need to provide subclass of `AppConfig`. Then, the user
of application need to reference it in `INSTALLED_APPS` setting either by
app's package path, or by `AppConfig` subclass.
It is also stated that app's author ''can'' make the loading of his
`AppConfig` subclass by pointing `default_app_config` variable in
`__init__.py` to `AppConfig` subclass full dotted path:
You can make your application load this AppConfig subclass by default as
follows:
{{{
# rock_n_roll/__init__.py
default_app_config = 'rock_n_roll.apps.RockNRollConfig'
}}}
Note that is not "required", nor "should" - you just "can". I treat it as
"you can, if you will".
[https://docs.djangoproject.com/en/3.1/ref/applications/#django.apps.AppConfig.ready
Later on], it is stated that
`AppConfig.ready()`
Subclasses can override this method to perform initialization tasks such
as registering signals.
And finally, in [https://docs.djangoproject.com/en/3.1/topics/signals
/#connecting-receiver-functions "Signals"] documentation page, it is
suggested to import application's signals in `.ready()` method.
It is fleetingly stated, though, in
[https://docs.djangoproject.com/en/3.1/ref/applications/#configuring-
applications "Configuring applications"] that:
If there is no `default_app_config`, Django uses the base `AppConfig`
class
Which means that application author's `AppConfig` subclass ''will not even
evaluated'' - so, nor `.ready()` is called, too.
The docs should explicitly **warn** (at least) an user that is is the case
if app's author missed to define `default_app_config`, or user itself
referenced application not by full `AppConfig` class.
== The code
It can do better, too.
There is clear condition that custom `AppConfig` subclass is skipped,
here:
{{{
else:
try:
# If this works, the app module specifies an app config
class.
entry = module.default_app_config
except AttributeError:
# Otherwise, it simply uses the default app config class.
return cls(entry, module)
}}}
github
https://github.com/django/django/blob/stable/3.1.x/django/apps/config.py#L110
An user, again, should be explicitly warned (at least) that it is the
case, for example with log event of `WARNING` level.
Silently ignoring such a crucial nuance is worst possible way. Users can
([https://stackoverflow.com/search?q=django+signals+not+working and will,
in my experience]) assume, for example, that subclassing `AppConfig` and
overriding `.ready()` method is enough for registering their signals,
which is far from truth. The solution could be to use full `AppConfig`
paths, but seems like no one using it.
In our current project, there is about 30 installed apps (w/o our own),
and none of them referenced by `AppConfig`s subclasses:
{{{
INSTALLED_APPS = [
'polymorphic',
'watchman',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'collectfast',
'django.contrib.staticfiles',
'dal',
'dal_select2',
'dal_queryset_sequence',
'django_admin_env_notice',
'django.contrib.admin',
'django.contrib.admindocs',
'adminsortable2',
'ckeditor',
'ckeditor_uploader',
'easy_pdf',
'rest_framework',
'django_filters',
'djoser',
'social_django',
'rest_social_auth',
'axes',
'corsheaders',
'drf_yasg',
'django_extensions',
'django.contrib.postgres',
'psqlextra',
'versatileimagefield',
]
}}}
The most popular reusable apps also suggest usage of just package path in
their docs:
https://www.django-rest-framework.org/#installation
https://django-allauth.readthedocs.io/en/latest/installation.html#django
https://github.com/django-extensions/django-extensions#installing-it
https://github.com/adamchainz/django-cors-headers#setup
--
Ticket URL: <https://code.djangoproject.com/ticket/32186>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* type: Uncategorized => Bug
--
Ticket URL: <https://code.djangoproject.com/ticket/32186#comment:1>
* status: new => closed
* resolution: => duplicate
* component: Uncategorized => Core (Other)
Comment:
This is a duplicate of #31180, which will have default app configs
[https://docs.djangoproject.com/en/dev/releases/3.2/#automatic-appconfig-
discovery automatically discovered from Django 3.2].
--
Ticket URL: <https://code.djangoproject.com/ticket/32186#comment:2>