Skip to main content

Troubleshooting Guide

Quick Troubleshooting

Common issues and solutions when using Django-CFG. Use Details to expand specific problems, or search with Ctrl+F.

Common issues and solutions when using django-cfg.

Configuration Issues

ConfigurationError: At least one database must be configured

Problem:

django_cfg.core.exceptions.ConfigurationError: At least one database must be configured

Cause: No databases defined in configuration.

Solution:

from django_cfg import DjangoConfig
from django_cfg.models import DatabaseConfig

class MyConfig(DjangoConfig):
databases = {
"default": DatabaseConfig(
engine="django.db.backends.sqlite3",
name="db.sqlite3",
)
}
Quick Fix

Django requires at least one database with the alias "default". Even if you don't use a database, configure SQLite as a placeholder.

ConfigurationError: 'default' database is required

Problem:

ConfigurationError: 'default' database is required

Cause: Databases configured but no 'default' alias.

Solution:

databases = {
"default": DatabaseConfig(...), # ← Must have 'default'
"other": DatabaseConfig(...),
}
Required Alias

Django always requires a database with the alias "default". You can have additional databases, but "default" is mandatory.

ValidationError: SECRET_KEY must be at least 50 characters

Problem:

ValidationError: SECRET_KEY must be at least 50 characters long

Solution:

# Generate a secure secret key
from django.core.management.utils import get_random_secret_key

secret_key = get_random_secret_key()

# Or use environment variable
secret_key = "${SECRET_KEY}"
Security Critical

Never use short or weak SECRET_KEY in production:

  • ❌ "changeme" - Too short and obvious
  • ❌ "django-insecure-..." - Development only
  • ✅ Generate with: python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
  • ✅ Store in environment variables, never commit to git
Extra inputs are not permitted

Problem:

pydantic_core._pydantic_core.ValidationError: Extra inputs are not permitted

Cause: Using invalid or non-existent field name in configuration.

Solution:

# Ensure you only use valid DjangoConfig fields
class MyConfig(DjangoConfig):
security_domains = [...] # ✅ Valid field
# Check documentation for all available fields
Finding Valid Fields

Check available fields in:

Import Errors

ImportError: cannot import name 'get_current_config'

Problem:

ImportError: cannot import name 'get_current_config' from 'django_cfg.core.config'

Solution:

# Update import path
from django_cfg.core import get_current_config # ✅ Correct

# Or
from django_cfg.core.state import get_current_config # ✅ Also correct

# Not this:
# from django_cfg.core.config import get_current_config # ❌ Old path
Correct Import Paths

Django-CFG reorganized imports in recent versions. Always import from:

  • from django_cfg import DjangoConfig, get_current_config (recommended)
  • from django_cfg.core import DjangoConfig, get_current_config (also works)
ImportError: cannot import name 'DjangoConfig'

Problem:

ImportError: cannot import name 'DjangoConfig'

Solution:

# Make sure django-cfg is installed
pip install django-cfg

# Correct import
from django_cfg import DjangoConfig

# Or
from django_cfg.core import DjangoConfig
Installation Check

Verify django-cfg is installed:

pip show django-cfg
# Should show package information

pip list | grep django-cfg
# Should list the package
Circular Import Error

Problem:

ImportError: cannot import name 'DjangoConfig' from partially initialized module 'django_cfg'

Cause: Circular import between settings and config.

Solution:

# settings.py
from myproject.config import MyConfig # ✅ Import config class

config = MyConfig()
globals().update(config.get_all_settings())

# Don't import settings in config.py!
Circular Import Prevention

Never do this:

# config.py
from django.conf import settings # ❌ Creates circular import

Instead, use lazy imports or dependency injection:

# config.py
def get_setting_value():
from django.conf import settings # ✅ Lazy import inside function
return settings.SOME_VALUE

Database Issues

Database routing references non-existent databases

Problem:

ConfigurationError: Database routing references non-existent databases: {'analytics'}

Cause: migrate_to references database that doesn't exist.

Solution:

databases = {
"default": DatabaseConfig(...),
"analytics": DatabaseConfig(
...,
migrate_to="default", # ← Ensure 'default' exists
),
}
Database Routing Validation

Django-CFG validates that all migrate_to references point to existing databases. Common mistakes:

  • ❌ Typo in database alias: migrate_to="defualt"
  • ❌ Reference to database not in databases dict
  • ✅ Always reference existing database aliases
django.db.utils.OperationalError: FATAL: database does not exist

Problem: Database connection fails because database doesn't exist.

Solution:

# Create the database first
createdb mydb

# Or configure to create automatically
databases = {
"default": DatabaseConfig(
...,
options={"autocommit": True},
)
}
Database Creation

PostgreSQL:

createdb mydb
# Or with user: createdb -U myuser mydb

MySQL:

mysql -u root -p -e "CREATE DATABASE mydb;"

SQLite: Django creates SQLite databases automatically if they don't exist.

Migrations not running on correct database

Problem: Migrations run on wrong database in multi-database setup.

Solution:

# Use migrate_to to control where migrations run
databases = {
"default": DatabaseConfig(...),
"analytics": DatabaseConfig(
...,
migrate_to="default", # Migrations run here
),
}

# Then run
python manage.py migrate # Migrates default only
python manage.py migrate_all # Migrates all with routing
Multi-Database Migration Control

The migrate_to parameter controls where migrations execute:

  • Not set: Migrations run on the database itself
  • Set to another db: Migrations run on the target database
  • Common pattern: All migrations on default, data on separate databases

See Multi-Database Guide for detailed patterns.

CORS Issues

CORS header 'Access-Control-Allow-Origin' missing

Problem: Browser console shows CORS error in production.

Cause: Production requires security_domains configuration.

Solution:

# Production: Configure security_domains
security_domains = [
"frontend.example.com", # ✅ Any format works
"https://api.example.com", # ✅ With protocol
"staging.example.com:3000", # ✅ With port
]

# Development: No configuration needed!
# debug=True automatically enables CORS_ALLOW_ALL_ORIGINS
Environment-Aware CORS Configuration

Django-CFG automatically configures CORS based on environment:

Development Mode (debug=True or no security_domains):

  • CORS_ALLOW_ALL_ORIGINS = True - Fully open
  • ALLOWED_HOSTS = ['*'] - All hosts accepted
  • ✅ Docker IPs work automatically
  • ✅ No configuration needed!

Production Mode (when security_domains set):

  • CORS_ALLOWED_ORIGINS - Generated from security_domains
  • CORS_ALLOW_CREDENTIALS = True - Credentials enabled
  • ALLOWED_HOSTS - Strict whitelist
  • ✅ Auto-normalized from any domain format
  • ✅ CORS middleware auto-inserted
CORS allows all origins in production

Problem: CORS_ALLOW_ALL_ORIGINS = True in production.

Cause: Not setting security_domains in production configuration.

Solution:

# REQUIRED in production - set security_domains
security_domains = [
"example.com",
"api.example.com",
]

# This automatically switches to strict whitelist mode
Security Critical: CORS Misconfiguration

Django-CFG behavior:

  • Development (debug=True or no security_domains) → CORS fully open
  • 🔒 Production (when security_domains set) → Strict whitelist only

Allowing all origins in production is a critical security vulnerability:

  • 🔒 CSRF attacks - Any site can make requests to your API
  • 🔒 Data theft - Malicious sites can steal user data
  • 🔒 Session hijacking - Attackers can exploit user sessions

Production checklist:

  • REQUIRED: Set security_domains with production domains
  • ✅ Use HTTPS domains (handled by reverse proxy)
  • ✅ Include only trusted domains
  • ✅ Set debug = False
  • ❌ Never leave security_domains empty/None in production

Example validation:

if env.env_mode == "production":
if not config.security_domains:
raise ValueError("CRITICAL: security_domains required in production!")

Static Files Issues

Static files not found (404)

Problem: Static files return 404 in production.

Solution:

# Collect static files
python manage.py collectstatic --noinput

# Ensure WhiteNoise is configured (automatic in django-cfg)
# Check STATIC_ROOT
python manage.py show_config | grep STATIC
WhiteNoise Auto-Configuration

Django-CFG automatically configures WhiteNoise for static file serving:

  • Middleware added - WhiteNoise middleware inserted
  • STATIC_ROOT set - Points to staticfiles/ directory
  • Compression enabled - GZip compression for performance
  • Caching configured - Far-future cache headers

Production checklist:

  1. Run collectstatic before deployment
  2. Set STATIC_ROOT in environment if needed
  3. Verify static files exist in STATIC_ROOT
Static files not updating

Problem: CSS/JS changes not reflected.

Solution:

# Clear browser cache
# Or bust cache with versioning

# In development, ensure DEBUG=True
debug = True
Cache Busting Strategies

Development:

  • Hard refresh browser: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac)
  • Disable cache in DevTools (Network tab → "Disable cache")
  • Set DEBUG = True to disable aggressive caching

Production:

  • Use Django's ManifestStaticFilesStorage (automatic with WhiteNoise)
  • Files get hash suffix: style.cssstyle.a4b3c2d1.css
  • Changes create new hash → browser fetches new file

Background Tasks Issues

Tasks not being processed

Problem: Tasks enqueued but never execute.

Cause: Worker not running.

Solution:

# Start ReArq worker
rearq main:rearq worker

# Or with specific queues
rearq main:rearq worker --queues default high_priority

# Check worker status
rearq main:rearq info
Worker Must Be Running

ReArq requires a separate worker process to execute tasks:

  • Common mistake: Enqueueing tasks without running worker
  • Development: Run rearq main:rearq worker in separate terminal
  • Production: Use process manager (systemd, supervisor, Docker)

Check if worker is running:

ps aux | grep rearq_worker  # Should show running process
Redis connection refused

Problem:

redis.exceptions.ConnectionError: Error 61 connecting to localhost:6379. Connection refused.

Cause: Redis not running.

Solution:

# Start Redis
redis-server

# Or use Docker
docker run -d -p 6379:6379 redis

# Verify connection
redis-cli ping # Should return PONG
Redis Installation & Setup

Install Redis:

  • macOS: brew install redis && brew services start redis
  • Ubuntu: sudo apt install redis-server && sudo systemctl start redis
  • Docker: docker run -d -p 6379:6379 redis

Verify Redis:

redis-cli ping  # Should return: PONG
redis-cli info | grep uptime # Show uptime

Configure custom Redis URL:

# In config.py
tasks: TaskConfig = TaskConfig(
redis_url="redis://localhost:6379/0",
)
Tasks stuck in queue

Problem: Tasks enqueued but status shows "pending" forever.

Solution:

# Check worker logs
rearq main:rearq worker --verbose

# Clear stuck tasks
rearq main:rearq flush

# Restart worker
# Kill existing worker and start fresh
Debugging Stuck Tasks

Common causes of stuck tasks:

  1. Worker crashed - Check logs for exceptions
  2. Task timeout - Increase timeout in task config
  3. Deadlock - Task waiting for another task
  4. Queue mismatch - Task sent to queue worker isn't watching

Debug steps:

# 1. Check worker is processing
rearq main:rearq worker --verbose # Watch logs

# 2. Check Redis has messages
redis-cli LLEN "arq:queue:default" # Queue length

# 3. Manually retry task
rearq main:rearq retry <task_id>

Email Issues

Email not sending

Problem: Emails not being sent/received.

Solution:

# Check email configuration
from django.core.mail import send_mail

send_mail(
'Test Subject',
'Test message',
'from@example.com',
['to@example.com'],
fail_silently=False, # ← Show errors
)

# Or use test command
python manage.py test_email to@example.com
Email Testing & Debugging

Development:

  • Use console backend: backend="django.core.mail.backends.console.EmailBackend"
  • Emails print to console instead of sending

Testing:

# In config.py
email = EmailConfig(
backend="django.core.mail.backends.console.EmailBackend", # Development
)

# Or use file backend
email = EmailConfig(
backend="django.core.mail.backends.filebased.EmailBackend",
file_path="tmp/emails", # Emails saved as files
)

Check configuration:

python manage.py show_config | grep EMAIL
SMTP authentication failed

Problem:

SMTPAuthenticationError: (535, b'5.7.8 Authentication failed')

Solution:

# Verify credentials
email = EmailConfig(
backend="django.core.mail.backends.smtp.EmailBackend",
host="smtp.gmail.com",
port=587,
use_tls=True,
user="${EMAIL_USER}", # Check this
password="${EMAIL_PASSWORD}", # Check this
)

# For Gmail, use App Password (not regular password)
Gmail App Passwords Required

Gmail requires App Passwords for SMTP:

  1. Enable 2-Factor Authentication on Google account
  2. Go to Google Account → Security → App Passwords
  3. Generate new app password for "Mail"
  4. Use generated password (16 chars, no spaces)

Common SMTP configurations:

# Gmail
email = EmailConfig(
host="smtp.gmail.com",
port=587,
use_tls=True,
)

# Outlook/Office365
email = EmailConfig(
host="smtp.office365.com",
port=587,
use_tls=True,
)

# SendGrid
email = EmailConfig(
host="smtp.sendgrid.net",
port=587,
use_tls=True,
user="apikey", # Literal "apikey"
password="${SENDGRID_API_KEY}",
)

Ngrok Issues

Ngrok tunnel not starting

Problem: runserver_ngrok fails to start tunnel.

Solution:

# Install pyngrok
pip install pyngrok

# Set auth token (for custom subdomain)
export NGROK_AUTH_TOKEN=your_token_here

# Or configure in settings
ngrok = NgrokConfig(
enabled=True,
auth_token="${NGROK_AUTH_TOKEN}",
)
Ngrok Setup

Install pyngrok:

pip install pyngrok

Get auth token:

  1. Sign up at https://ngrok.com
  2. Go to Dashboard → Auth Token
  3. Copy token and set environment variable

Configure in Django-CFG:

# config.py
ngrok = NgrokConfig(
enabled=True,
auth_token="${NGROK_AUTH_TOKEN}",
subdomain="myapp", # Optional: fixed subdomain (requires paid plan)
)

Start server with ngrok:

python manage.py runserver_ngrok
# Output: Ngrok tunnel: https://myapp.ngrok.io
Ngrok tunnel URL changes

Problem: Tunnel URL changes every restart (random subdomain).

Solution:

# Use custom subdomain (requires ngrok auth token)
ngrok = NgrokConfig(
enabled=True,
auth_token="${NGROK_AUTH_TOKEN}",
subdomain="myapp", # Fixed subdomain
)
Ngrok Free vs Paid

Free plan:

  • ✅ Random subdomain: https://abc123.ngrok.io
  • ❌ Changes on every restart
  • ✅ Good for testing webhooks

Paid plan ($8/month):

  • ✅ Custom subdomain: https://myapp.ngrok.io
  • ✅ Persistent URL across restarts
  • ✅ Multiple tunnels simultaneously

Alternatives to paid ngrok:

  • localtunnel - Free, but less stable
  • serveo - Free SSH tunneling
  • pagekite - Free tier available

Payment System Issues

Payment webhook not working

Problem: Webhooks not being received/processed.

Solution:

# Verify webhook URL is publicly accessible
# Use ngrok for local development
python manage.py runserver_ngrok

# Check webhook secret is correct
payments = PaymentsConfig(
providers={
"nowpayments": NowPaymentsConfig(
ipn_secret="${NOWPAYMENTS_IPN_SECRET}", # ← Verify this
),
},
)

# Check webhook logs
# Monitor webhook endpoint for incoming requests
Webhook Requirements

Webhooks require publicly accessible URL:

  • Won't work: localhost, 127.0.0.1, private IPs
  • Will work: Public domain, ngrok tunnel

Development setup:

# Start ngrok tunnel
python manage.py runserver_ngrok

# Copy ngrok URL from output
# Configure webhook URL in payment provider dashboard
# Example: https://abc123.ngrok.io/payments/webhook/nowpayments/

Verify webhook:

  1. Check webhook URL is registered in provider dashboard
  2. Verify IPN secret matches provider settings
  3. Monitor webhook logs for incoming requests
  4. Test with provider's webhook testing tool
Payment test mode not working

Problem: Test payments fail or use real money.

Solution:

# Enable test mode
payments = PaymentsConfig(
enabled=True,
test_mode=True, # ← Ensure this is True
providers={...},
)

# Use test API keys
# Most providers have separate test/sandbox keys
Test Mode Critical

Always use test mode in development:

  • 🔒 Prevents real charges - No actual money transferred
  • 🔒 Use sandbox API keys - Separate from production
  • 🔒 Test with test cryptocurrencies - No real crypto needed

NowPayments test mode:

payments = PaymentsConfig(
test_mode=True, # ✅ Test mode
providers={
"nowpayments": NowPaymentsConfig(
api_key="${NOWPAYMENTS_SANDBOX_API_KEY}", # Sandbox key
ipn_secret="${NOWPAYMENTS_SANDBOX_IPN_SECRET}",
),
},
)

Verify test mode:

# Check configuration
python manage.py show_config | grep -i test

# Payments should show "sandbox" or "test" in API URLs

Debug Tools

Using check_settings command
# Validate all Django settings
python manage.py check_settings

# Shows:
# - Required settings present
# - Security issues
# - Configuration warnings
check_settings Command

Django-CFG provides check_settings command to validate configuration:

  • ✅ Checks required settings (SECRET_KEY, DATABASES, etc.)
  • ✅ Validates security settings (ALLOWED_HOSTS, CORS, etc.)
  • ✅ Warns about common misconfigurations
  • ✅ Shows configuration recommendations

Example output:

✓ SECRET_KEY configured (50+ characters)
✓ Database 'default' configured
✓ ALLOWED_HOSTS configured for production
⚠ DEBUG=True in production (should be False)
Using show_config command
# Display current configuration
python manage.py show_config

# Show specific section
python manage.py show_config --section databases
python manage.py show_config --section security
show_config Options

Display modes:

# Full configuration
python manage.py show_config

# Specific section
python manage.py show_config --section databases
python manage.py show_config --section security
python manage.py show_config --section middleware

# Sanitized output (hides secrets)
python manage.py show_config --sanitize

# Debug mode (verbose)
python manage.py show_config --debug

Useful for:

  • Verifying configuration values
  • Debugging environment variable expansion
  • Checking middleware order
  • Validating database settings
Enable Debug Mode
# Temporary debug mode
DEBUG = True
startup_info_mode = StartupInfoMode.FULL

# Enables:
# - Detailed error pages
# - Full startup information
# - Template debug
# - SQL query logging
Debug Mode Settings

Development:

# config.py
debug = True
startup_info_mode = StartupInfoMode.FULL

Production:

# config.py
debug = False # ← Must be False
startup_info_mode = StartupInfoMode.NONE

What DEBUG=True enables:

  • Detailed error pages with full traceback
  • Template variable inspection
  • SQL query logging (performance impact)
  • Static file serving (slow, use only in dev)

Security risk in production:

  • 🔒 Exposes source code paths
  • 🔒 Shows environment variables
  • 🔒 Reveals database queries
  • 🔒 Displays sensitive settings
Debug Warnings with Traceback

Problem: You see RuntimeWarnings like:

RuntimeWarning: Accessing the database during app initialization is discouraged.

But you don't know WHERE in your code it's happening.

Solution: Enable debug_warnings to see full stack traceback:

config.py
from django_cfg import DjangoConfig

class MyConfig(DjangoConfig):
project_name: str = "My Project"

# Enable warnings traceback in development
debug_warnings: bool = True # ← Shows full stack trace

Example Output:

================================================================================
⚠️ WARNING TRACEBACK (to help find the source)
================================================================================
File "/path/to/your/code/apps.py", line 42, in ready
self.setup_database()
File "/path/to/your/code/apps.py", line 55, in setup_database
MyModel.objects.all() # ← HERE IS THE PROBLEM!
^^^^^^^^^^^^^^^^^^^^

--------------------------------------------------------------------------------
⚠️ WARNING MESSAGE:
RuntimeWarning: Accessing the database during app initialization is discouraged.
To fix this warning, avoid executing queries in AppConfig.ready() or when your
app modules are imported.
================================================================================
Common Issues Found

Database access in AppConfig.ready():

# ❌ Bad - queries during import
def ready(self):
from .models import MyModel
MyModel.objects.create(...)

# ✅ Good - use post_migrate signal
def ready(self):
from django.db.models.signals import post_migrate
post_migrate.connect(self.setup_data, sender=self)

Model queries at module level:

# ❌ Bad - runs during import
from .models import MyModel
DEFAULT_SETTINGS = MyModel.objects.first()

# ✅ Good - lazy evaluation
def get_default_settings():
from .models import MyModel
return MyModel.objects.first()

What debug_warnings shows:

  • 📍 Full stack trace to the exact line
  • 🎯 Which app/file is causing the warning
  • 🔍 Complete call chain from Django startup
  • ⚡ Works for RuntimeWarning, DeprecationWarning, etc.
Check Django Configuration
# Run Django system checks
python manage.py check

# Run deployment checks
python manage.py check --deploy

# Check specific tag
python manage.py check --tag security
Django Check Framework

Available check tags:

# Security checks
python manage.py check --tag security

# Database checks
python manage.py check --tag database

# Model checks
python manage.py check --tag models

# Compatibility checks
python manage.py check --tag compatibility

# All deployment checks
python manage.py check --deploy

Common issues detected:

  • Missing SECRET_KEY or weak SECRET_KEY
  • DEBUG=True in production
  • Missing ALLOWED_HOSTS
  • Insecure middleware configuration
  • Missing staticfiles configuration

Performance Issues

Settings generation slow

Problem: Application startup is slow.

Cause: Settings generated on every request (should be cached).

Solution:

# Settings are cached by default
# Clear cache manually if needed
config.invalidate_cache()

# Or use cached property
@property
def my_settings(self):
if not hasattr(self, '_my_settings_cache'):
self._my_settings_cache = expensive_operation()
return self._my_settings_cache
Configuration Caching

Django-CFG automatically caches configuration:

  • Settings cached - Generated once per application lifecycle
  • Environment variables cached - Expanded once
  • Model imports cached - No repeated imports

Performance benchmarks:

  • First generation: ~50-100ms
  • Cached access: <1ms
  • No runtime overhead after startup

When to invalidate cache:

  • Environment variables changed
  • Configuration file modified
  • Dynamic settings updated
Database queries slow

Problem: Database operations are slow.

Solution:

# Enable connection pooling
databases = {
"default": DatabaseConfig(
...,
conn_max_age=600, # Connection pooling
options={
"connect_timeout": 10,
},
),
}

# Use database indexes
# Use select_related() and prefetch_related()
# Enable query logging to identify slow queries
Database Performance Optimization

Connection pooling:

databases = {
"default": DatabaseConfig(
conn_max_age=600, # Keep connections alive for 10 minutes
conn_health_checks=True, # Validate connections before use
),
}

Query optimization:

# N+1 query problem - BAD
for user in User.objects.all():
print(user.profile.bio) # Extra query per user

# Optimized with select_related - GOOD
for user in User.objects.select_related('profile'):
print(user.profile.bio) # Single JOIN query

Debug slow queries:

# config.py
LOGGING = {
'loggers': {
'django.db.backends': {
'level': 'DEBUG', # Log all SQL queries
},
},
}

Tools for profiling:

  • django-debug-toolbar - Visual query profiler
  • django-silk - Request profiling
  • nplusone - Detect N+1 queries

Getting More Help

Enable Verbose Logging

import logging

logging.basicConfig(level=logging.DEBUG)

# Or configure in LOGGING
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'root': {
'handlers': ['console'],
'level': 'DEBUG',
},
}

Collect Debug Information

When reporting issues, include:

# Django-cfg version
pip show django-cfg

# Django version
python -m django --version

# Python version
python --version

# Configuration (sanitized)
python manage.py show_config --sanitize

# Django checks
python manage.py check --deploy

# Full traceback
# (Copy entire error with traceback)

Community Support

  • GitHub Issues: Report bugs
  • Discussions: Ask questions
  • Stack Overflow: Tag with django-cfg
  • Discord/Slack: Real-time help

Professional Support

For enterprise customers:

  • Priority bug fixes
  • Migration assistance
  • Custom feature development
  • Architecture review

Common Patterns

Development vs Production

# Use environment-specific configuration

# Development
class DevelopmentConfig(DjangoConfig):
env_mode = EnvironmentMode.DEVELOPMENT
debug = True
startup_info_mode = StartupInfoMode.FULL

# Production
class ProductionConfig(DjangoConfig):
env_mode = EnvironmentMode.PRODUCTION
debug = False
startup_info_mode = StartupInfoMode.NONE
security_domains = ["example.com"]

Testing Configuration

# Test-specific settings
class TestConfig(DjangoConfig):
env_mode = EnvironmentMode.TEST
databases = {
"default": DatabaseConfig(
engine="django.db.backends.sqlite3",
name=":memory:",
)
}
email = EmailConfig(
backend="django.core.mail.backends.locmem.EmailBackend",
)

Environment Variables

# Load from .env file
from dotenv import load_dotenv
load_dotenv()

# Use in configuration
secret_key = "${SECRET_KEY}"
databases = {
"default": DatabaseConfig(
name="${DATABASE_NAME}",
user="${DATABASE_USER}",
password="${DATABASE_PASSWORD}",
)
}

Next Steps