Django Settings
Setting up and managing your Django project's configuration is one of the first steps in building a robust web application. Django's settings system allows you to control various aspects of your project's behavior, from database connections to security features.
Introduction to Django Settings
Django settings are managed through a Python module, typically named settings.py
, which contains all the configuration options for your project. When you create a new Django project using the startproject
command, Django automatically generates this file with sensible defaults.
The settings file controls everything from database configuration and installed apps to security settings and template configurations. Understanding how to properly configure and manage these settings is essential for developing Django applications.
The Settings File Structure
Let's examine the structure of a typical settings.py
file generated by Django:
# settings.py
# Import path module
import os
from pathlib import Path
# Build paths inside the project
BASE_DIR = Path(__file__).resolve().parent.parent
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-abcdefghijklmnopqrstuvwxyz123456789'
# 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',
# Your custom apps here
]
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 = [
{
'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 = 'myproject.wsgi.application'
# Database configuration
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# 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_L10N = 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 Settings Components
Let's explore some of the most important settings in detail:
Debug Mode
DEBUG = True
The DEBUG
setting controls Django's debug mode. In development, you typically set this to True
to get detailed error pages. In production, you should always set it to False
to avoid exposing sensitive information.
Secret Key
SECRET_KEY = 'django-insecure-abcdefghijklmnopqrstuvwxyz123456789'
The SECRET_KEY
is a cryptographic key used for security-sensitive operations like sessions and CSRF protection. Never expose this key in public repositories. For production, consider storing it in environment variables.
Installed Apps
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Your custom apps here
'myapp',
]
The INSTALLED_APPS
setting is a list of all Django applications that are active in your project. This includes both Django's built-in applications and your custom ones.
Database Configuration
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
The DATABASES
setting configures database connections. By default, Django uses SQLite, but you can configure it to use other database engines like PostgreSQL, MySQL, or Oracle.
Static Files
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
These settings control how Django handles static files like CSS, JavaScript, and images.
Environment-Specific Settings
In real-world applications, you'll often need different settings for development, testing, and production environments. Here's how you can manage environment-specific settings:
Using Multiple Settings Files
A common approach is to create multiple settings files:
myproject/
settings/
__init__.py
base.py # Common settings
development.py # Development-specific settings
production.py # Production-specific settings
In base.py
, you define common settings:
# settings/base.py
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent.parent
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
# ...
]
# Other common settings
In environment-specific files like development.py
, you import base settings and override as needed:
# settings/development.py
from .base import *
DEBUG = True
SECRET_KEY = 'development-key'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
In production.py
, you would have production-specific configurations:
# settings/production.py
from .base import *
import os
DEBUG = False
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
ALLOWED_HOSTS = ['.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': '5432',
}
}
# Additional security settings
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
To use these settings, specify the settings module when running Django commands:
python manage.py runserver --settings=myproject.settings.development
Using Environment Variables
Another approach is to use environment variables to control settings:
# settings.py
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
# Use environment variable, fallback to a default
DEBUG = os.environ.get('DJANGO_DEBUG', 'False') == 'True'
# Get secret key from environment
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
# Database configuration from environment variables
DATABASES = {
'default': {
'ENGINE': os.environ.get('DB_ENGINE', 'django.db.backends.sqlite3'),
'NAME': os.environ.get('DB_NAME', BASE_DIR / 'db.sqlite3'),
'USER': os.environ.get('DB_USER', ''),
'PASSWORD': os.environ.get('DB_PASSWORD', ''),
'HOST': os.environ.get('DB_HOST', ''),
'PORT': os.environ.get('DB_PORT', ''),
}
}
Using django-environ for Environment Management
For more sophisticated environment management, consider using the django-environ
package:
pip install django-environ
Here's how to set it up:
# settings.py
import environ
import os
env = environ.Env(
# Set default values
DEBUG=(bool, False)
)
# Read .env file if it exists
environ.Env.read_env()
# Build paths
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Use environment variables with defaults
DEBUG = env('DEBUG')
SECRET_KEY = env('SECRET_KEY')
DATABASES = {
'default': env.db(), # Expects DATABASE_URL environment variable
}
EMAIL_CONFIG = env.email_url() # Expects EMAIL_URL environment variable
vars().update(EMAIL_CONFIG)
Then, create a .env
file in your project root:
DEBUG=True
SECRET_KEY=your-secret-key
DATABASE_URL=sqlite:///db.sqlite3
EMAIL_URL=smtp://user:password@localhost:25
This approach simplifies managing environment variables and provides type casting.
Best Practices for Django Settings
-
Never expose sensitive information: Keep your
SECRET_KEY
and database credentials secure. -
Use environment variables: Store sensitive information in environment variables, not in code.
-
Keep settings DRY: Use a base settings file for common configurations, then extend it for different environments.
-
Use version control wisely: Add
.env
files to.gitignore
to prevent committing sensitive information. -
Keep DEBUG = False in production: Always set
DEBUG = False
in production to prevent exposing sensitive information. -
Be explicit with ALLOWED_HOSTS: In production, always specify the allowed host names in the
ALLOWED_HOSTS
setting. -
Group related settings: Keep related settings together for easier management.
Real-World Example: Complete Settings Configuration
Let's see how we might set up a more complete Django project with properly configured settings:
# settings.py
import os
import environ
from pathlib import Path
# Initialize environment variables
env = environ.Env(
DEBUG=(bool, False),
ALLOWED_HOSTS=(list, []),
)
# Read .env file if it exists
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('ALLOWED_HOSTS')
# 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.apps.UsersConfig',
'products.apps.ProductsConfig',
]
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',
]
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(),
}
# Custom user model
AUTH_USER_MODEL = 'users.User'
# Password validation
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {
'min_length': 9,
}
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = env('TIME_ZONE', default='UTC')
USE_I18N = True
USE_L10N = 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')]
# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# Security settings for production
if not DEBUG:
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
# CORS settings
CORS_ALLOWED_ORIGINS = env.list('CORS_ALLOWED_ORIGINS', default=[])
# REST Framework settings
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
}
# Email settings
EMAIL_CONFIG = env.email_url('EMAIL_URL', default='consolemail://')
vars().update(EMAIL_CONFIG)
# Logging configuration
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {message}',
'style': '{',
},
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
'file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR, 'logs/django.log'),
'formatter': 'verbose',
},
},
'loggers': {
'django': {
'handlers': ['console', 'file'],
'level': 'INFO',
'propagate': True,
},
},
}
Accessing Settings in Your Code
You can access settings from anywhere in your Django code using the settings API:
from django.conf import settings
# Access settings in your code
debug_mode = settings.DEBUG
database_name = settings.DATABASES['default']['NAME']
static_url = settings.STATIC_URL
# Use settings in your application
if settings.DEBUG:
# Do something in debug mode
print(f"Running in debug mode with database: {database_name}")
This approach ensures that you're always using the correct settings values based on the current environment.
Summary
Django's settings provide a powerful way to configure and customize your web application. Key takeaways include:
- The
settings.py
file controls all aspects of your Django project configuration - Different environments (development, production) require different settings
- Best practices include using environment variables for sensitive information
- Properly structuring your settings prevents security issues
- Tools like django-environ simplify environment variable management
Proper settings configuration is fundamental to building secure, maintainable Django applications. By following the practices outlined in this guide, you'll be well on your way to creating robust Django projects.
Additional Resources
- Django Official Documentation on Settings
- Django-environ Package Documentation
- 12-Factor App Methodology (see especially the "Config" factor)
Exercises
- Create a Django project with separate settings files for development and production environments.
- Implement django-environ in an existing project to manage environment variables.
- Set up a project that uses PostgreSQL in production but SQLite in development.
- Configure email settings to use the console backend in development and an SMTP server in production.
- Implement proper security settings for a production environment, including HTTPS configurations.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)