Skip to main content

Django Configuration

When developing a Django application, configuring your project properly is crucial. Proper configuration ensures your application runs efficiently, securely, and can adapt to different environments like development, testing, and production. In this guide, we'll explore Django's configuration system and learn how to set up your project for success.

Introduction to Django Settings

Django's settings system is the central configuration point for all Django projects. It allows you to configure everything from database connections to internationalization preferences.

The most important file in Django configuration is settings.py, which is automatically created when you start a new project using the django-admin startproject command.

The Default Settings File

When you create a new Django project, a default settings.py file is generated that looks something like this:

python
# settings.py (simplified example)
import os
from pathlib import Path

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

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-some-random-string'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'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 = 'myproject.urls'

TEMPLATES = [...]

WSGI_APPLICATION = 'myproject.wsgi.application'

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

# Password validation
AUTH_PASSWORD_VALIDATORS = [...]

# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True

# Static files (CSS, JavaScript, Images)
STATIC_URL = 'static/'

# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

Key Configuration Settings

Let's explore the most important settings you'll need to understand:

Debug Mode

python
DEBUG = True

The DEBUG setting controls whether Django's debug mode is active. During development, it provides detailed error pages with traceback information. In production, it must be set to False to avoid exposing sensitive information.

Secret Key

python
SECRET_KEY = 'your-secret-key'

The secret key is used for cryptographic signing in Django. It's crucial to keep this value secret and to use different keys in development and production.

Allowed Hosts

python
ALLOWED_HOSTS = ['example.com', 'www.example.com']

This setting is a security measure that specifies which host/domain names your Django site can serve. When DEBUG=False, you must explicitly list all domains that your site should respond to.

Database Configuration

python
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydatabase',
'USER': 'mydatabaseuser',
'PASSWORD': 'mypassword',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}

This configures the database connection. The default SQLite configuration works for development, but for production, you'll typically want to use a more robust database like PostgreSQL, MySQL, or Oracle.

Installed Apps

python
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp', # Your custom apps
'third_party_app', # Third-party apps
]

This list tells Django which applications are active for this project. When you create new apps with python manage.py startapp, you need to add them here.

Static and Media Files

python
# Static files (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]

# Media files (User-uploaded files)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

These settings configure how Django handles static files (CSS, JavaScript, images) and media files (user uploads).

Environment-Based Configuration

In real-world applications, you'll want different configurations for development, testing, and production environments. Here's how to set up environment-specific settings:

Using Multiple Settings Files

A common approach is to create multiple settings files:

myproject/
settings/
__init__.py
base.py
development.py
production.py
test.py

The base.py contains common settings, while environment-specific files import from base and override certain values:

python
# base.py
import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent.parent

INSTALLED_APPS = [
'django.contrib.admin',
# ...more apps
]

# Common settings...
python
# development.py
from .base import *

DEBUG = True
SECRET_KEY = 'dev-secret-key'

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

# Development-specific settings...
python
# production.py
from .base import *

DEBUG = False
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
ALLOWED_HOSTS = ['example.com', 'www.example.com']

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT'),
}
}

# Production-specific settings...

To use these different settings, you can set the DJANGO_SETTINGS_MODULE environment variable:

bash
# For development
export DJANGO_SETTINGS_MODULE=myproject.settings.development

# For production
export DJANGO_SETTINGS_MODULE=myproject.settings.production

Using Environment Variables with django-environ

A popular approach is to use environment variables for configuration using the django-environ package:

bash
pip install django-environ

Then in your settings file:

python
import environ

env = environ.Env(
# Set default values
DEBUG=(bool, False),
)

# Read .env file if it exists
environ.Env.read_env()

SECRET_KEY = env('SECRET_KEY')
DEBUG = env('DEBUG')

DATABASES = {
'default': env.db(), # Parses DATABASE_URL environment variable
}

EMAIL_CONFIG = env.email_url(
'EMAIL_URL', default='smtp://user:password@localhost:25')

Your .env file (which should not be committed to version control) might look like:

SECRET_KEY=my-super-secret-key
DEBUG=True
DATABASE_URL=postgres://user:password@localhost:5432/mydatabase
EMAIL_URL=smtp://user:password@smtp.example.com:587

Practical Example: Complete Settings Configuration

Let's put everything together with a comprehensive, production-ready configuration example:

python
import os
import environ
from pathlib import Path

# Initialize environment variables
env = environ.Env(DEBUG=(bool, False))
environ.Env.read_env()

# Build paths
BASE_DIR = Path(__file__).resolve().parent.parent

# Security settings
SECRET_KEY = env('SECRET_KEY')
DEBUG = env('DEBUG')
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['localhost', '127.0.0.1'])

# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',

# Third-party apps
'rest_framework',
'corsheaders',

# Local apps
'users',
'products',
]

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # For static files in production
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# URLs and templates
ROOT_URLCONF = 'myproject.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 = 'myproject.wsgi.application'

# Database
DATABASES = {
'default': env.db(),
}

# 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 = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True

# 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'

# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# Default primary key field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# Security settings for production
if not DEBUG:
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
X_FRAME_OPTIONS = 'DENY'
SECURE_CONTENT_TYPE_NOSNIFF = True

# REST Framework settings
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
}

# CORS settings
CORS_ALLOWED_ORIGINS = env.list('CORS_ALLOWED_ORIGINS', default=[])

# Logging configuration
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {message}',
'style': '{',
},
},
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR, 'logs/django.log'),
'formatter': 'verbose',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'root': {
'handlers': ['console', 'file'],
'level': 'INFO',
},
}

Best Practices for Django Configuration

  1. Never hardcode sensitive information like secret keys, passwords, or API tokens
  2. Use environment variables for sensitive or environment-specific settings
  3. Keep development and production settings separate
  4. Default to secure settings (always set DEBUG=False in production)
  5. Use a version control system but exclude sensitive files (like .env)
  6. Document your settings so other developers understand their purpose
  7. Keep your settings organized by logical grouping (security, database, static files, etc.)
  8. Use sensible defaults but allow overrides for flexibility

Common Configuration Issues and Solutions

Problem: "ImproperlyConfigured" errors

Solution: This usually happens when a required setting is missing. Verify all required settings are defined and your settings module can be imported correctly.

Problem: Static files not being served in production

Solution: Ensure STATIC_ROOT is set, run python manage.py collectstatic, and configure your web server to serve files from that directory.

Problem: Different behavior between development and production

Solution: Review environment-specific settings and ensure they're being loaded correctly. Check the DJANGO_SETTINGS_MODULE environment variable.

Problem: Database migration errors

Solution: Verify your database settings are correct and the database user has appropriate permissions.

Summary

Django's configuration system is powerful and flexible, allowing you to customize virtually every aspect of your application. Proper configuration is essential for making your Django project secure, efficient, and maintainable:

  1. Use the settings.py file to configure your Django project
  2. Separate settings for different environments (development, production)
  3. Use environment variables for sensitive information
  4. Configure databases, static files, and security settings appropriately
  5. Follow best practices to maintain a secure and efficient application

By mastering Django's configuration system, you'll build more robust and adaptable web applications that work well across different environments.

Additional Resources

Exercise: Configure a Multi-Environment Django Project

Try creating a Django project with separate configurations for development and production:

  1. Create a new Django project
  2. Restructure the settings into a package with base.py, development.py, and production.py
  3. Configure environment-specific databases
  4. Set up environment variables for sensitive information
  5. Configure static file handling differently for each environment
  6. Test switching between configurations using the DJANGO_SETTINGS_MODULE environment variable

This exercise will help you understand how to structure a real-world Django project with proper configuration practices.



If you spot any mistakes on this website, please let me know at feedback@compilenrun.com. I’d greatly appreciate your feedback! :)