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:
# 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
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
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
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
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
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
# 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:
# 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...
# 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...
# 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:
# 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:
pip install django-environ
Then in your settings file:
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:
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
- Never hardcode sensitive information like secret keys, passwords, or API tokens
- Use environment variables for sensitive or environment-specific settings
- Keep development and production settings separate
- Default to secure settings (always set
DEBUG=False
in production) - Use a version control system but exclude sensitive files (like
.env
) - Document your settings so other developers understand their purpose
- Keep your settings organized by logical grouping (security, database, static files, etc.)
- 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:
- Use the
settings.py
file to configure your Django project - Separate settings for different environments (development, production)
- Use environment variables for sensitive information
- Configure databases, static files, and security settings appropriately
- 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
- Official Django Settings Documentation
- Django Deployment Checklist
- django-environ Documentation
- Two Scoops of Django - Popular book with extensive coverage of Django best practices
Exercise: Configure a Multi-Environment Django Project
Try creating a Django project with separate configurations for development and production:
- Create a new Django project
- Restructure the settings into a package with
base.py
,development.py
, andproduction.py
- Configure environment-specific databases
- Set up environment variables for sensitive information
- Configure static file handling differently for each environment
- 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! :)