'Error when deploying django web application with daphne: Requested setting INSTALLED_APPS, but settings are not configured

I have been battling with an error that I encountered when trying to deploy a django application that uses channels.

Error in heroku logs

Starting process with command `daphne friendship.asgi:application --port 52589 --bind 0.0.0.0 -v2`
2021-06-02T19:51:57.338171+00:00 heroku[web.1]: Process exited with status 1
2021-06-02T19:51:57.105387+00:00 app[web.1]: Traceback (most recent call last):
2021-06-02T19:51:57.105477+00:00 app[web.1]: File "/app/.heroku/python/bin/daphne", line 8, in <module>
2021-06-02T19:51:57.105796+00:00 app[web.1]: sys.exit(CommandLineInterface.entrypoint())
2021-06-02T19:51:57.105861+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/daphne/cli.py", line 170, in entrypoint
2021-06-02T19:51:57.106200+00:00 app[web.1]: cls().run(sys.argv[1:])
2021-06-02T19:51:57.106259+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/daphne/cli.py", line 232, in run
2021-06-02T19:51:57.106713+00:00 app[web.1]: application = import_by_path(args.application)
2021-06-02T19:51:57.106774+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/daphne/utils.py", line 12, in import_by_path
2021-06-02T19:51:57.107059+00:00 app[web.1]: target = importlib.import_module(module_path)
2021-06-02T19:51:57.107118+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/importlib/__init__.py", line 127, in import_module
2021-06-02T19:51:57.107436+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level)
2021-06-02T19:51:57.107491+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
2021-06-02T19:51:57.107783+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
2021-06-02T19:51:57.107986+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
2021-06-02T19:51:57.108196+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
2021-06-02T19:51:57.108533+00:00 app[web.1]: File "<frozen importlib._bootstrap_external>", line 790, in exec_module
2021-06-02T19:51:57.108768+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
2021-06-02T19:51:57.108967+00:00 app[web.1]: File "./friendship/asgi.py", line 5, in <module>
2021-06-02T19:51:57.109233+00:00 app[web.1]: import errands.routing
2021-06-02T19:51:57.109290+00:00 app[web.1]: File "./errands/routing.py", line 2, in <module>
2021-06-02T19:51:57.110045+00:00 app[web.1]: from . import consumers
2021-06-02T19:51:57.110094+00:00 app[web.1]: File "./errands/consumers.py", line 3, in <module>
2021-06-02T19:51:57.110331+00:00 app[web.1]: from .models import RoomMessage, PrivateChatRoom
2021-06-02T19:51:57.110378+00:00 app[web.1]: File "./errands/models.py", line 3, in <module>
2021-06-02T19:51:57.110708+00:00 app[web.1]: from accounts.models import CustomUser
2021-06-02T19:51:57.110756+00:00 app[web.1]: File "./accounts/models.py", line 2, in <module>
2021-06-02T19:51:57.111794+00:00 app[web.1]: from django.contrib.auth.base_user import BaseUserManager
2021-06-02T19:51:57.111866+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/contrib/auth/base_user.py", line 48, in <module>
2021-06-02T19:51:57.112224+00:00 app[web.1]: class AbstractBaseUser(models.Model):
2021-06-02T19:51:57.112320+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/db/models/base.py", line 108, in __new__
2021-06-02T19:51:57.112739+00:00 app[web.1]: app_config = apps.get_containing_app_config(module)
2021-06-02T19:51:57.112789+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/apps/registry.py", line 253, in get_containing_app_config
2021-06-02T19:51:57.113140+00:00 app[web.1]: self.check_apps_ready()
2021-06-02T19:51:57.113193+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/apps/registry.py", line 135, in check_apps_ready
2021-06-02T19:51:57.113463+00:00 app[web.1]: settings.INSTALLED_APPS
2021-06-02T19:51:57.113518+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/conf/__init__.py", line 82, in __getattr__
2021-06-02T19:51:57.113802+00:00 app[web.1]: self._setup(name)
2021-06-02T19:51:57.113852+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/django/conf/__init__.py", line 63, in _setup
2021-06-02T19:51:57.114115+00:00 app[web.1]: raise ImproperlyConfigured(
2021-06-02T19:51:57.114363+00:00 app[web.1]: 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.

asgi.py

import os

from django.core.asgi import get_asgi_application

import errands.routing
import django
from channels.routing import get_default_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'friendship.settings')
django.setup()

application = get_default_application()

wsgi.py


import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'friendship.settings')

application = get_wsgi_application()

routing.py

from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import errands.routing

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter(
            errands.routing.websocket_urlpatterns
        )
    )
})

settings.py

from pathlib import Path
import os
import dotenv

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

dotenv.load_dotenv()


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.environ.get("DEBUG")

ALLOWED_HOSTS = ['127.0.0.1', 'friendshipweb.herokuapp.com']


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'accounts',
    'errands',
    'channels',
]

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',
]

ROOT_URLCONF = 'friendship.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, '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',
            ],
        },
    },
]

WSGI_APPLICATION = 'friendship.wsgi.application'
ASGI_APPLICATION = 'friendship.routing.application'

CHANNEL_LAYERS = {
    "default": {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            'hosts': [(os.environ.get('REDIS_URL'), 6379)]
        }
    }
}


# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

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
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]

STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

AUTH_USER_MODEL = 'accounts.CustomUser'

Procfile

web: daphne friendship.asgi:application --port $PORT --bind 0.0.0.0 -v2
worker: python manage.py runworker channels --settings=friendship.settings -v2

I have tried already to set the environment variable in heroku, changing asgi structure, trying different procfile configurations, but nothing seems to work. I would really appreciate it if someone could help me, thanks.



Solution 1:[1]

I ran into a similar problem and for me the fix was that I imported some files that needed django to be initialized before setting the variable and initializing django.

Looking at your stacktrace, your problem is probably the same. When importing errands.routing, django needs to be already setup. Change your asgi.py to the following and see if it works:

import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'friendship.settings')
django.setup()

from django.core.asgi import get_asgi_application
import errands.routing
from channels.routing import get_default_application


application = get_default_application()

Solution 2:[2]

Here's the one with the stock authentication tie-in to Django:

import os

import django
from channels.auth import AuthMiddlewareStack  # new import
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application

asgi_app = get_asgi_application()

import chat.routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jobs.settings')
django.setup()

application = ProtocolTypeRouter({
  'http': asgi_app,
  'websocket': AuthMiddlewareStack(  # new
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),  # new
})

Notice the ordering!

Notice someone somewhere else says that you have to initialize asgi_app before importing chat.routing (or something like that).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jonas
Solution 2 Abstract Space Crack