URL-Based Database Configuration
Django-CFG uses URL-based database configuration for simplicity and security.
Why URL-Based Configuration?
Benefits:
- ✅ Single string for all connection parameters
- ✅ Easy to override with environment variables
- ✅ Standard format across different databases
- ✅ No hardcoded credentials in code
- ✅ Compatible with 12-factor app methodology
URL Format
{engine}://{user}:{password}@{host}:{port}/{database}?{options}Database Engines
SQLite
# File-based database
url: str = "sqlite:///db/mydb.sqlite3"
# Absolute path
url: str = "sqlite:////absolute/path/to/db.sqlite3"
# In-memory database
url: str = "sqlite:///:memory:"PostgreSQL
# Full URL with all parameters
url: str = "postgresql://user:password@localhost:5432/dbname"
# Default port (5432)
url: str = "postgresql://user:password@localhost/dbname"
# Short form (postgres instead of postgresql)
url: str = "postgres://user:password@localhost/dbname"
# With SSL
url: str = "postgresql://user:pass@localhost/db?sslmode=require"
# With connection timeout
url: str = "postgresql://user:pass@localhost/db?connect_timeout=10"
# Multiple options
url: str = "postgresql://user:pass@localhost/db?sslmode=require&connect_timeout=10"MySQL
# MySQL connection
url: str = "mysql://user:password@localhost:3306/dbname"
# With charset
url: str = "mysql://user:pass@localhost/db?charset=utf8mb4"Oracle
# Oracle connection
url: str = "oracle://user:password@localhost:1521/dbname"Configuration Examples
Development (SQLite)
# api/environment/loader.py
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class DatabaseConfig(BaseSettings):
url: str = Field(default="sqlite:///db/dev.sqlite3")
model_config = SettingsConfigDict(
env_prefix="DATABASE__",
env_nested_delimiter="__",
)# .env (optional override)
DATABASE__URL="sqlite:///db/dev.sqlite3"Production (PostgreSQL)
# api/environment/loader.py
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class DatabaseConfig(BaseSettings):
url: str = Field(default="sqlite:///db/default.sqlite3")
model_config = SettingsConfigDict(
env_prefix="DATABASE__",
env_nested_delimiter="__",
)# System ENV or Docker environment
DATABASE__URL="postgresql://user:${DB_PASSWORD}@db.example.com:5432/production"Environment Variable Override
# .env
DATABASE__URL="postgresql://user:password@localhost:5432/mydb"# api/environment/loader.py - automatically reads DATABASE__URL
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class DatabaseConfig(BaseSettings):
url: str = Field(default="sqlite:///db/default.sqlite3") # Fallback
model_config = SettingsConfigDict(
env_prefix="DATABASE__",
env_nested_delimiter="__",
)Settings Integration
Django-CFG automatically converts URLs to Django’s DATABASES format:
# api/config.py
from django_cfg import DjangoConfig, DatabaseConfig
from .environment import env
class MyDjangoConfig(DjangoConfig):
databases = {
"default": DatabaseConfig.from_url(url=env.database.url)
}
# Generate Django settings
config = MyDjangoConfig()Advanced Options
Connection Pooling
# PostgreSQL with connection pooling
url: str = "postgresql://user:pass@localhost/db?pool_size=20&max_overflow=10"SSL Configuration
# Require SSL
url: str = "postgresql://user:pass@localhost/db?sslmode=require"
# Verify SSL certificate
url: str = "postgresql://user:pass@localhost/db?sslmode=verify-full&sslrootcert=/path/to/cert"Timeouts
# Connection timeout
url: str = "postgresql://user:pass@localhost/db?connect_timeout=10"
# Statement timeout
url: str = "postgresql://user:pass@localhost/db?options=-c statement_timeout=30000"Character Encoding
# UTF-8 for MySQL
url: str = "mysql://user:pass@localhost/db?charset=utf8mb4"
# Client encoding for PostgreSQL
url: str = "postgresql://user:pass@localhost/db?client_encoding=UTF8"Security Best Practices
1. Never Hardcode Credentials
❌ Bad:
url: str = "postgresql://admin:MyPassword123@localhost/db"✅ Good:
# System environment variable
export DATABASE__URL="postgresql://admin:${DB_PASSWORD}@localhost/db"
export DB_PASSWORD="MyPassword123"Or in .env file (gitignored):
DATABASE__URL="postgresql://admin:MyPassword123@localhost/db"2. Use Environment Variables in Production
# api/environment/loader.py
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class DatabaseConfig(BaseSettings):
url: str = Field(default="sqlite:///db/default.sqlite3")
model_config = SettingsConfigDict(
env_prefix="DATABASE__",
env_nested_delimiter="__",
)# Production environment
export DATABASE__URL="postgresql://prod_user:${DB_PASSWORD}@db.example.com/prod_db"3. Different Credentials Per Environment
# Development (.env file)
DATABASE__URL="postgresql://dev_user:dev_pass@localhost/dev_db"# Production (system ENV or Docker)
DATABASE__URL="postgresql://prod_user:${DB_PASSWORD}@db.example.com/prod_db"Troubleshooting
Special Characters in Password
If password contains special characters, URL-encode them:
# Password: p@ssw0rd!
# URL-encoded: p%40ssw0rd%21
url: str = "postgresql://user:p%40ssw0rd%21@localhost/db"Or use Python’s urllib:
from urllib.parse import quote_plus
password = "p@ssw0rd!"
encoded_password = quote_plus(password)
url = f"postgresql://user:{encoded_password}@localhost/db"Connection Issues
# Test connection
python manage.py check --database default
# Verify URL parsing
python manage.py shell
>>> from django.conf import settings
>>> print(settings.DATABASES['default'])See Also
- Database Configuration - Configure databases
- Environment Variables - Environment configuration
- Configuration Models - Configuration API