Fix AppRegistryNotReady in Celery and Django Scripts
Fix Apps not loaded yet and settings not configured errors in Celery workers, cron scripts, and Gunicorn config: set DJANGO_SETTINGS_MODULE, call django.setup() first, and avoid early model imports.
Problem statement
A Celery worker, a standalone script run from cron, or a custom Gunicorn configuration crashes during startup with one of these:
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are
not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call
settings.configure() before accessing settings.
Both mean code touched Django (settings, models, or something that imports models) before Django was initialised. manage.py and wsgi.py do the initialisation for you, which is why the same code works in runserver and in Gunicorn but fails in other entry points. This guide shows the correct start-up order for each entry point and how to find the import that runs too early.
- Set
DJANGO_SETTINGS_MODULEbefore anything imports Django settings (in code withos.environ.setdefault, or in the service environment). - In standalone scripts, call
django.setup()before importing models; better, turn the script into a management command. - In
celery.py, set the settings module before creating the Celery app, useconfig_from_object("django.conf:settings", namespace="CELERY")andautodiscover_tasks(), and do not import models at module level there. - Remove model imports from app
__init__.pyfiles, settings, andapps.pymodule level; import them insideready()or functions. - Read the traceback bottom-up to find the first project file that triggered the import.
Step-by-step solution
1. Find the triggering import
Read the traceback from the bottom up and look for the first file from your project:
File "/srv/myapp/current/config/celery.py", line 6, in <module>
from orders.models import Order
File "/srv/myapp/current/orders/models.py", line 3, in <module>
class Order(models.Model):
...
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
Here config/celery.py imports a model at module level, before Django is set up.
2. Fix Celery's entry point
The standard layout:
# config/celery.py
import os
from celery import Celery
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
app = Celery("config")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()
# config/__init__.py
from .celery import app as celery_app
__all__ = ("celery_app",)
- The settings module is set before anything reads settings.
config_from_objectreads settings lazily.autodiscover_tasks()imports each app'stasks.pyafter Django is set up (Celery's Django integration callsdjango.setup()when the worker starts).- No model imports in this file. Import models inside task modules, which are loaded after setup.
Start workers with the project module: celery -A config worker. If the service environment sets DJANGO_SETTINGS_MODULE, it takes precedence over setdefault, which is what you want for per-environment settings.
3. Fix standalone scripts
A script run with python scripts/cleanup.py must initialise Django itself, in this order:
# scripts/cleanup.py
import os
import sys
import django
sys.path.insert(0, "/srv/myapp/current")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
django.setup()
from orders.models import Order # noqa: E402 (must come after setup)
Order.objects.filter(status="draft", created__lt=...).delete()
Imports of models placed above django.setup() (for example sorted to the top by an import formatter) bring the error back. A management command avoids all of this, because manage.py performs setup before running it:
# orders/management/commands/cleanup_drafts.py
from django.core.management.base import BaseCommand
from orders.models import Order
class Command(BaseCommand):
help = "Delete stale draft orders"
def handle(self, *args, **options):
deleted, _ = Order.objects.filter(status="draft").delete()
self.stdout.write(f"deleted {deleted}")
Run it from cron or a systemd timer with python manage.py cleanup_drafts.
4. Remove early model imports inside the project
Django imports each app's package, then its apps.py, then its models.py, while populating the registry. Code that imports models during that process runs too early:
# orders/__init__.py — BAD
from .models import Order
# orders/apps.py — BAD: module-level import
from django.apps import AppConfig
from .models import Order
class OrdersConfig(AppConfig):
name = "orders"
# orders/apps.py — GOOD: import inside ready()
from django.apps import AppConfig
class OrdersConfig(AppConfig):
name = "orders"
def ready(self):
from . import signals # noqa: F401
Settings files must never import models or modules that import models. Use string references instead (for example AUTH_USER_MODEL = "accounts.User", dotted paths for backends and middleware).
To refer to a model class without importing it at module level, use apps.get_model("orders", "Order") inside functions, or settings.AUTH_USER_MODEL / get_user_model() for the user model.
5. Gunicorn configuration and hooks
A gunicorn.conf.py is loaded before the WSGI application. Hooks such as post_fork or when_ready that touch Django models must call django.setup() first or, better, avoid Django entirely. Keep the configuration file to Gunicorn settings.
6. Test entry points outside Django's runner
# Celery app loads cleanly
DJANGO_SETTINGS_MODULE=config.settings.production python -c "from config.celery import app; print(app.main)"
# Worker starts and lists tasks
celery -A config inspect registered --timeout 5
# Script runs in the service environment
sudo -u myapp bash -c 'set -a; . /etc/myapp.env; set +a; cd /srv/myapp/current && .venv/bin/python scripts/cleanup.py'
Verification check:
The worker log shows celery@host ready. and lists your tasks under [tasks], and the script or command completes without an import error when run exactly as cron or systemd runs it.
Explanation
Django's app registry is filled in django.setup(): settings are loaded, each installed app is imported, and each app's models are registered. Model classes need the registry to exist when they are defined, so importing models.py before setup raises AppRegistryNotReady, and reading settings before DJANGO_SETTINGS_MODULE is known raises ImproperlyConfigured. manage.py, wsgi.py, asgi.py, and Celery's Django integration all perform setup in the right order; problems appear in entry points that do not, or when module-level imports sneak model loading in before setup.
Edge cases / notes
pytest and tests
pytest-django sets up Django before collecting tests; a conftest.py that imports models at module level can still run too early if it is loaded before the plugin configures Django. Import inside fixtures.
Circular imports that look similar
ImportError: cannot import name 'X' from partially initialized module is a circular import, not a registry problem, although both often involve models.py importing from services.py and back. Move shared code to a module that does not import models at top level.
When to automate this
Run the Celery import check and each script or command in CI with production settings. A short smoke test that starts a worker and calls inspect registered catches entry-point regressions before deploy.
Next steps
- Set up Celery properly with Configure Redis and Celery for Django Production.
- If workers start but tasks do not run, see Celery Not Running in Django Production: Debugging Guide.
- Turn scripts into scheduled commands with Schedule Django Management Commands with Cron or systemd Timers.
- For the same kind of start-up failure in Gunicorn, see Fix Gunicorn "Worker failed to boot".
FAQ
What does "Apps aren't loaded yet" mean?
Code imported a model or used the app registry before django.setup() finished. Move the import after setup or into a function.
How do I use Django models in a standalone Python script?
Set DJANGO_SETTINGS_MODULE, call django.setup(), then import models. A management command does this for you and is usually the better choice.
Why does Celery raise AppRegistryNotReady at startup?
celery.py or a module it imports loads models at module level. Keep celery.py free of model imports and let autodiscover_tasks() load task modules.
Can I import models in an app's init.py?
No. App packages are imported before models are ready. Import models where they are used, or in AppConfig.ready().