Configuration Models
Django-CFG uses Pydantic v2 models for type-safe, validated configuration.
Why Type-Safe Configuration? Type-safe configuration catches errors at startup instead of runtime, provides IDE autocomplete, and enables static type checking with mypy/pyright.
Quick Start
Python Config
from django_cfg import DjangoConfig
from pydantic import BaseModel
class DatabaseConfig(BaseModel):
url: str = "sqlite:///db/default.sqlite3"
class MyProjectConfig(DjangoConfig):
# Core settings
secret_key: str = "your-secret-key-here"
debug: bool = True
project_name: str = "My Project"
# Database
database: DatabaseConfig = DatabaseConfig()
# Services (optional)
# email: EmailConfig = EmailConfig()
# telegram: TelegramConfig = TelegramConfig()YAML Config
secret_key: "dev-secret-key"
debug: true
project_name: "My Project"
database:
url: "sqlite:///db/default.sqlite3"
# Optional services
# email:
# backend: "console"
# telegram:
# bot_token: "your-token"from django_cfg import DjangoConfig, load_config
# Load from YAML
config = load_config() # Reads config.yamlConfiguration Topics
Core Configuration
- DjangoConfig - Base configuration class
- Security Settings - Security, CORS, SSL configuration
- Environment - Environment detection and variables
Infrastructure
- Database - Database configuration
- Cache - ✨ Auto Redis cache from
redis_url(Redis, LocMem, Dummy) - Logging - Logging configuration
Deployment
- Docker Configuration - YAML + environment variables for Docker
Services
- Email - Email services (SendGrid, SMTP, Console)
- Telegram - Telegram bot configuration
- Background Tasks - ReArq task configuration
Django Integrations
- Admin & UI - Unfold admin interface
- API - DRF, Spectacular, JWT
- Payments - Payment providers (NowPayments, Stripe)
Key Features
Type Safety
Automatic Type Validation Pydantic validates all types automatically at instantiation time, preventing runtime errors.
# Pydantic validates types automatically
class MyConfig(DjangoConfig):
debug: bool = True
max_connections: int = 100
timeout: float = 30.0
# âś… This works
config = MyConfig(debug=True, max_connections=50)
# ❌ This fails with validation error
config = MyConfig(debug="yes", max_connections="fifty")See validation error output
ValidationError: 2 validation errors for MyConfig
debug
Input should be a valid boolean [type=bool_type]
max_connections
Input should be a valid integer [type=int_type]Environment Variables
Automatic Loading
from pydantic_settings import BaseSettings
class DatabaseConfig(BaseSettings):
url: str = "sqlite:///db/default.sqlite3"
class Config:
env_prefix = "DATABASE_"
# Automatically reads DATABASE_URL from environment
config = DatabaseConfig()Manual Loading
import os
class DatabaseConfig(BaseModel):
url: str = os.getenv("DATABASE_URL", "sqlite:///db/default.sqlite3")Environment Variables in Production Always use environment variables for secrets (API keys, passwords) in production. Never commit them to version control.
YAML Configuration
Basic YAML
secret_key: "dev-secret-key"
debug: true
project_name: "My Project"
database:
url: "postgresql://localhost/mydb"
email:
backend: "console"With Environment Variables
# Use ${VAR_NAME} for environment variable substitution
secret_key: "${SECRET_KEY}"
debug: false
project_name: "My Project"
database:
url: "${DATABASE_URL}"
email:
host: "${EMAIL_HOST}"
password: "${EMAIL_PASSWORD}"# Load from YAML
from django_cfg import load_config
config = load_config() # Reads config.yamlYAML Best Practice
Keep sensitive values in environment variables and reference them in YAML with ${VAR_NAME} syntax.
Validation
from pydantic import Field, field_validator
class MyConfig(DjangoConfig):
secret_key: str = Field(..., min_length=50)
max_connections: int = Field(default=100, ge=1, le=1000)
@field_validator('secret_key')
def validate_secret_key(cls, v):
if v == "changeme":
raise ValueError("Please change the default secret key")
return vPydantic Validators
Use field_validator for custom validation logic. Validators run automatically during configuration instantiation.
Configuration Patterns
Development vs Production
Using Properties
from django_cfg import DjangoConfig, Environment
class MyConfig(DjangoConfig):
@property
def debug(self) -> bool:
return Environment.current() == Environment.DEVELOPMENT
@property
def database_url(self) -> str:
if Environment.is_production():
return "postgresql://prod-db/main"
return "sqlite:///db/dev.sqlite3"Separate Configs
class BaseConfig(DjangoConfig):
project_name: str = "My Project"
class DevConfig(BaseConfig):
debug: bool = True
database_url: str = "sqlite:///dev.db"
class ProdConfig(BaseConfig):
debug: bool = False
database_url: str = "postgresql://prod-db/main"
# Select based on environment
import os
config = ProdConfig() if os.getenv("ENV") == "production" else DevConfig()Nested Configuration
class DatabaseConfig(BaseModel):
url: str
pool_size: int = 5
class CacheConfig(BaseModel):
backend: str = "redis"
location: str = "redis://localhost:6379/1"
class MyConfig(DjangoConfig):
database: DatabaseConfig
cache: CacheConfigOrganize Complex Configs Use nested Pydantic models to organize complex configurations into logical groups.
Optional Features
class MyConfig(DjangoConfig):
# Optional email configuration
email: Optional[EmailConfig] = None
# Enable optional features
enable_telegram: bool = False
enable_payments: bool = FalseExample: Conditional Feature Enabling
class MyConfig(DjangoConfig):
# Enable features based on environment
enable_telegram: bool = Field(
default_factory=lambda: os.getenv("ENABLE_TELEGRAM", "false") == "true"
)
enable_payments: bool = Field(
default_factory=lambda: os.getenv("ENABLE_PAYMENTS", "false") == "true"
)See Also
Configuration Deep Dive
- Type-Safe Configuration - Why type safety matters
- Environment - Environment detection and YAML config
- Database - Database configuration details
Docker Deployment
- Docker Configuration - Layered config strategy for Docker
- Docker Overview - Complete Docker deployment guide