django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet

Hello

My django project wont run when deployed in a container, but runs fine localy.

Full stacktrace:

Traceback (most recent call last):
  File "/usr/local/bin/daphne", line 8, in <module>
    sys.exit(CommandLineInterface.entrypoint())
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/daphne/cli.py", line 171, in entrypoint
    cls().run(sys.argv[1:])
  File "/usr/local/lib/python3.12/site-packages/daphne/cli.py", line 233, in run
    application = import_by_path(args.application)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/daphne/utils.py", line 12, in import_by_path
    target = importlib.import_module(module_path)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/importlib/__init__.py", line 90, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 995, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/app/webGui/asgi.py", line 17, in <module>
    from xentisControl.routing import websocket_urlpatterns
  File "/app/xentisControl/routing.py", line 4, in <module>
    from . import consumer
  File "/app/xentisControl/consumer.py", line 7, in <module>
    from xentisControl.xentisController import startXentis, stopXentis, stopPodman, startPodman, statXentis
  File "/app/xentisControl/xentisController.py", line 7, in <module>
    from .models import ServerConfig, Servers
  File "/app/xentisControl/models.py", line 11, in <module>
    class ServerConfig(models.Model):
  File "/usr/local/lib/python3.12/site-packages/django/db/models/base.py", line 127, in __new__
    app_config = apps.get_containing_app_config(module)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/django/apps/registry.py", line 260, in get_containing_app_config
    self.check_apps_ready()
  File "/usr/local/lib/python3.12/site-packages/django/apps/registry.py", line 138, in check_apps_ready
    raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

the stacktrace points to a models.py file looking like this:

from django.db import models


class ServerConfig(models.Model):
    def __getitem__(self, item):
        return getattr(self, item)

    uuid = models.CharField(db_column='UUID', max_length=50, primary_key=True)  # Field name made lowercase.
    server = models.CharField(db_column='SERVER', max_length=250)  # Field name made lowercase.
    customer = models.CharField(db_column='CUSTOMER', max_length=50)  # Field name made lowercase.
    server_type = models.CharField(db_column='SERVER_TYPE', max_length=20)  # Field name made lowercase.
    api_url = models.CharField(db_column='API_URL', max_length=255, blank=True, null=True)  # Field name made lowercase.
    json_config = models.JSONField(db_column='JSON_CONFIG', blank=True, null=True)  # Field name made lowercase.
    active = models.IntegerField(db_column='ACTIVE')  # Field name made lowercase.
    default_alert_type = models.CharField(db_column='DEFAULT_ALERT_TYPE', max_length=50)  # Field name made lowercase.
    create_ok_file = models.IntegerField(db_column='CREATE_OK_FILE')  # Field name made lowercase.
    insert_date = models.DateTimeField(db_column='INSERT_DATE')  # Field name made lowercase.
    update_date = models.DateTimeField(db_column='UPDATE_DATE', blank=True, null=True)  # Field name made lowercase.

    class Meta:
        managed = False
        db_table = 'server_config'

the asgi.py looks like this:

"""
ASGI config for webGui project.

It exposes the ASGI callable as a module-level variable named ``application``.

For more information on this file, see

"""

import os
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application

from xentisControl.routing import websocket_urlpatterns


# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webGui.settings")
application = get_asgi_application()


application = ProtocolTypeRouter({
    "http": application,
    "websocket": AllowedHostsOriginValidator(
            AuthMiddlewareStack(URLRouter(websocket_urlpatterns))),
    # add other protocols here
})

the settings.py is in the correct location and also found, because otherwise I would expect an other exception.
settings.py looks like this:

"""
Django settings for webGui project.

Generated by 'django-admin startproject' using Django 4.1.3.

For more information on this file, see


For the full list of settings and their values, see

"""

from pathlib import Path
import os

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production


# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "hidden"
#SECRET_KEY = os.getenv("SECRET_KEY")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
#DEBUG = os.getenv("DEBUG")
ALLOWED_HOSTS = ["*"]
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

# Define for which Customer the app is running
CUSTOMER = "hidden"

# Application definition

INSTALLED_APPS = [
    "daphne",
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    'django_auth_adfs',
    "logincheck",
    "alerter",
    "hostHealth",
    "xentisAlerter",
    "xentisServices",
    "xentisControl",
    "kskk",
    "pdmPortal",
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "whitenoise.middleware.WhiteNoiseMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    'django_auth_adfs.middleware.LoginRequiredMiddleware',
]

ROOT_URLCONF = "webGui.urls"

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [os.path.join(BASE_DIR,'bootstrap/templates')],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
            'libraries':{
                'template_filters': 'template_filters',
            }
        },
    },
]
ASGI_APPLICATION = "webGui.asgi.application"


# Database


DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django',
        'USER': 'django',
        'PASSWORD': 'django',
        'HOST': '10.2.1.38',
        'TIME_ZONE':'Europe/Berlin',
        'PORT': '1521',
    },
    'monitoring': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'monitoring',
        'USER': 'monitor',
        'PASSWORD': 'hidden',
        'HOST': '10.2.1.38',
        'TIME_ZONE':'Europe/Berlin',
        'PORT': '1521',
    },
    'xentisservices': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '${DB_NAME}',
        'USER': 'monitor',
        'PASSWORD': 'hidden',
        'HOST': '10.2.1.38',
        'TIME_ZONE':'Europe/Berlin',
        'PORT': '1521',
    }
}


# Password validation


AUTH_PASSWORD_VALIDATORS = [
    {
        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
    },
]


# Internationalization


LANGUAGE_CODE = "de-de"

TIME_ZONE = "Europe/Berlin"

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)


STATIC_ROOT = os.path.join(BASE_DIR, 'boot/static/')
STATIC_URL = "bootstrap/static/"
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'bootstrap/static')]

# Default primary key field type


DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

X_FRAME_OPTIONS = 'SAMEORIGIN'

CSP_DEFAULT_SRC = ["'none'"]
CSP_SCRIPT_SRC = ["'self'", "${ELASTIC}"]
CSP_STYLE_SRC = ["'self'", "${ELASTIC}"]
CSP_FRAME_SRC = ["'self'", "${ELASTIC}"]
CSRF_TRUSTED_ORIGINS = ["${HOST_IP}", "${HOST_NAME}", "${HOST_NAME}.${DOMAIN}", "${HOST_NAME}.${DOMAIN}:${HTTPS_PORT}", "hidden"]
DATA_UPLOAD_MAX_NUMBER_FIELDS = 200000


#ADFS Config
AUTH_USER_MODEL = 'kskk.User'
AUTH_ADFS = {
    "SERVER": "hidden",
    "CLIENT_ID": "hidden",
    "RELYING_PARTY_ID": "django.webgui",
    # Make sure to read the documentation about the AUDIENCE setting
    # when you configured the identifier as a URL!
    "AUDIENCE": "microsoft:identityserver:django.webgui",
    "CA_BUNDLE": 'bootstrap/static/adfs-cert/ca_bundle.crt',
    "CLAIM_MAPPING": {"first_name": "given_name",
                      "last_name": "family_name",
                      "email": "email",
                      "common_name": "commonname"},
    "USERNAME_CLAIM": "winaccountname",
    "GROUP_CLAIM": "group",
    "JWT_LEEWAY": 20,
    "MIRROR_GROUPS": True,
    "LOGIN_EXEMPT_URLS": [${LOGIN_EXEMPT_URLS}],
    "GROUP_TO_FLAG_MAPPING": {"is_staff": ["APP-AllCustomers-Xentis Produktiv"], "is_superuser": "Admin"},
}
LOGIN_URL = "django_auth_adfs:login"
LOGIN_REDIRECT_URL = "/"
CUSTOM_FAILED_RESPONSE_VIEW = 'dot.path.to.custom.views.login_failed'

AUTHENTICATION_BACKENDS = (
    'django_auth_adfs.backend.AdfsAuthCodeBackend',
)
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(name)s %(message)s'
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'verbose'
        },
    },
    'loggers': {
        'django_auth_adfs': {
            'handlers': ['console'],
            'level': 'DEBUG',
        },
    },
}

I have replaced some things with “hidden” to not share secret_keys, etc. The “${}” variables get set by our GITLAB CI/CD pipeline, i checked them they get set correctly.

Im out of idea where to check next or what the problem could be, so i hope someone on here can help. :slight_smile:

Cheers

After not having found anything in the forum for hours i decided to write this topic. Ironicaly enough, 2 mins after creating it i found this topic:

the issue was importing the websockets_urlpatterns bevor os.environ.setdefault(). I guess localy the path to settings.py was already cached from previous runs.

Cheers