cmcjake
cmcjake

Reputation: 159

Django Error 500 related to staticfiles when DEBUG = False

Here is my settings.py:

import os
import django_heroku

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = 'secret_key'

DEBUG = False

ALLOWED_HOSTS = ['*']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'corsheaders',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',
    'rest_framework',
    'django_celery_beat'
]

MIDDLEWARE = [
  'django.middleware.security.SecurityMiddleware',
  'django.contrib.sessions.middleware.SessionMiddleware',    
  'corsheaders.middleware.CorsMiddleware', # CORS support [keep load position] 
  'django.middleware.common.CommonMiddleware',
  #'django.middleware.cache.UpdateCacheMiddleware',
  #'django.middleware.common.CommonMiddleware',
  #'django.middleware.cache.FetchFromCacheMiddleware',
  'django.middleware.csrf.CsrfViewMiddleware',
  'corsheaders.middleware.CorsPostCsrfMiddleware',
  'django.contrib.auth.middleware.AuthenticationMiddleware',
  'django.contrib.messages.middleware.MessageMiddleware',
  'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

CORS_ORIGIN_WHITELIST = [
  "http://localhost:8080",
  "http://127.0.0.1:8080",
  "http://localhost:80"
]

CSRF_TRUSTED_ORIGINS = [
    'http://localhost:8080',
]

ROOT_URLCONF = 'django_backend.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        '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 = 'django_backend.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE':   'django.db.backends.postgresql',
        'NAME':     'name',
        'USER':     'user',
        'PASSWORD': "pw",
        'HOST':     'localhost',
        'PORT':     '5432'

    }
}


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

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))

CELERY_BROKER_URL = 'redis://url:port'
CELERY_RESULT_BACKEND = 'redis://url:port'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = TIME_ZONE

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },

    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        },
     'console':{
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}
DEBUG_PROPAGATE_EXCEPTIONS = True
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

STATIC_URL = '/static/'
django_heroku.settings(locals())

On my local server, I do not receive any errors. However in production, I get asset errors on any page that loads a static asset. For example trying to access the Django admin panel:

ValueError: Missing staticfiles manifest
entry for 'admin/css/base.css'

I have tried running python manage.py collectstatic which does not result in an error. It says 152 files collected in /staticfiles (confirmed they exist). Why is Django not able to find these static files? Another SO thread said to try setting ALLOWED_HOSTS to *, which I have as well. Other solutions such as trying the default static files settings configuration don't seem to work either.

Upvotes: 1

Views: 809

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476428

Django does not serve static files when the server is running in production (so with DEBUG = False).

As is specified in the documentation on Configuring static files:

In addition to these configuration steps, you’ll also need to actually serve the static files.

During development, if you use django.contrib.staticfiles, this will be done automatically by runserver when DEBUG is set to True (see django.contrib.staticfiles.views.serve()).

This method is grossly inefficient and probably insecure, so it is unsuitable for production.

See Deploying static files for proper strategies to serve static files in production environments.

If you thus want to run your server in production, you will need to set up the nginx/apache/... configuration to serve static files. collectstatic is used to collect the static files over the static directories, such that you can easily configure your server.

The documentation on serving static files in production has a section on how to configure an Apache server to serve static files. In most cases, one does not run Django and serves static files on the same server. Usually there are two servers that each handle one of the cases, or one uses a CDN or S3 storage.

As an alterantive, you can use the whitenoise package, it manages to improve certain aspects Django's static files will not, although it still might not be the best option to serve the static files through the same server as the Django server:

Isn’t serving static files from Python horribly inefficient?

The short answer to this is that if you care about performance and efficiency then you should be using WhiteNoise behind a CDN like CloudFront. If you’re doing that then, because of the caching headers WhiteNoise sends, the vast majority of static requests will be served directly by the CDN without touching your application, so it really doesn’t make much difference how efficient WhiteNoise is.

That said, WhiteNoise is pretty efficient. Because it only has to serve a fixed set of files it does all the work of finding files and determining the correct headers upfront on initialization. Requests can then be served with little more than a dictionary lookup to find the appropriate response. Also, when used with gunicorn (and most other WSGI servers) the actual business of pushing the file down the network interface is handled by the kernel’s very efficient sendfile syscall, not by Python.

Upvotes: 2

Related Questions