Skip to main content

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

config.py
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()

Configuration Topics

Core Configuration

Infrastructure

  • Database - Database configuration
  • Cache - ✨ Auto Redis cache from redis_url (Redis, LocMem, Dummy)
  • Logging - Logging configuration

Deployment

Services

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

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()
Environment Variables in Production

Always use environment variables for secrets (API keys, passwords) in production. Never commit them to version control.

YAML Configuration

config.yaml
secret_key: "dev-secret-key"
debug: true
project_name: "My Project"

database:
url: "postgresql://localhost/mydb"

email:
backend: "console"
config.py
# Load from YAML
from django_cfg import load_config

config = load_config() # Reads config.yaml
YAML 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 v
Pydantic Validators

Use field_validator for custom validation logic. Validators run automatically during configuration instantiation.

Configuration Patterns

Development vs Production

config.py
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"

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: CacheConfig
Organize 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 = False
Example: 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

Docker Deployment