Skip to main content

Cache Models

✨ Automatic Redis Cache - Zero Configuration!

Simply set redis_url in your config and Django-CFG automatically creates a Redis cache for you! No need for explicit cache_default configuration.

class MyConfig(DjangoConfig):
redis_url: str = "redis://localhost:6379/0" # That's it! 🎉

Django-CFG auto-selects the best cache backend: Redis for production, LocMem for development, DummyCache as safe fallback.

Django-CFG provides CacheConfig model for type-safe cache configuration with automatic Redis setup from redis_url.

CacheConfig

Type-safe cache backend configuration with environment-aware smart defaults.

Complete Model

from pydantic import BaseModel, Field, field_validator
from typing import Optional, Dict, Any

class CacheConfig(BaseModel):
"""Cache backend configuration"""

redis_url: Optional[str] = Field(
default=None,
description="Redis connection URL"
)
timeout: int = Field(
default=300,
description="Default timeout in seconds",
ge=0
)
max_connections: int = Field(
default=50,
description="Maximum Redis connections",
ge=1
)
key_prefix: str = Field(
default="",
description="Cache key prefix"
)
version: int = Field(
default=1,
description="Cache key version",
ge=1
)

# Advanced Redis settings
connection_pool_kwargs: Dict[str, Any] = Field(
default_factory=dict,
description="Redis connection pool parameters"
)

@field_validator('redis_url')
@classmethod
def validate_redis_url(cls, v):
"""Validate Redis URL format"""
if v and not v.startswith(('redis://', 'rediss://')):
raise ValueError("Redis URL must start with redis:// or rediss://")
return v

def to_django_config(self, environment: str, debug: bool) -> Dict[str, Any]:
"""Convert to Django cache configuration"""
from django_cfg.utils.smart_defaults import SmartDefaults

backend = SmartDefaults.get_cache_backend(
debug=debug,
redis_url=self.redis_url,
environment=environment
)

config = {
'BACKEND': backend,
'TIMEOUT': self.timeout,
'KEY_PREFIX': self.key_prefix,
'VERSION': self.version,
}

if backend == 'django_redis.cache.RedisCache' and self.redis_url:
config['LOCATION'] = self.redis_url
config['OPTIONS'] = {
'CONNECTION_POOL_KWARGS': {
'max_connections': self.max_connections,
**self.connection_pool_kwargs
}
}
elif backend == 'django.core.cache.backends.locmem.LocMemCache':
config['LOCATION'] = f'{self.key_prefix}-{id(self)}'

return config

🎯 How Auto Cache Works

Django-CFG uses a 3-tier priority system for cache configuration:

Priority Order:

  1. Explicit cache_default - You have full control
  2. Auto from redis_url ✨ - Magic happens here!
  3. Smart fallback - LocMem (dev) or FileBased (prod)

Auto-Creation Logic

When redis_url is set but cache_default is None:

# In CacheSettingsGenerator.generate():
if self.config.cache_default:
# User provided explicit config
caches["default"] = self.config.cache_default.to_django_config(...)
elif self.config.redis_url:
# ✨ AUTO-MAGIC: Create Redis cache automatically
logger.info(f"Auto-creating Redis cache from redis_url: {self.config.redis_url}")
caches["default"] = self._get_redis_cache_config()
else:
# Fallback to LocMem (dev) or FileBased (prod)
caches["default"] = self._get_default_cache_config()

Auto-generated config includes:

  • timeout=300 (5 minutes)
  • max_connections=50
  • key_prefix=project_name.lower().replace(" ", "_")

Smart Backend Selection

Django-CFG automatically selects the best cache backend based on environment and configuration:

ScenarioBackendredis_urlcache_defaultResult
Production + redis_urlRedisCache✅ Set❌ NoneAuto-created!
Production + explicitRedisCache✅ Set✅ SetManual control
Development + redis_urlRedisCache✅ Set❌ NoneAuto-created!
Development + No RedisLocMemCache❌ None❌ NoneFallback
Production + No RedisFileBasedCache❌ None❌ None⚠️ Creates tmp/

Usage Examples

config.py - Automatic Magic!
from django_cfg import DjangoConfig

class MyConfig(DjangoConfig):
secret_key: str = "your-secret-key"
debug: bool = False

# 🎉 MAGIC: Just set redis_url - cache auto-created!
redis_url: str = "redis://localhost:6379/0"
# No cache_default needed! Django-CFG handles it automatically

What Django-CFG auto-generates:

CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://localhost:6379/0',
'TIMEOUT': 300,
'KEY_PREFIX': 'my_config', # Auto from project_name
'VERSION': 1,
'OPTIONS': {
'CONNECTION_POOL_KWARGS': {
'max_connections': 50
}
}
}
}
Why This Works

Django-CFG's CacheSettingsGenerator automatically:

  1. Detects redis_url is set
  2. Creates CacheConfig with smart defaults
  3. Generates Redis cache configuration
  4. No tmp/ directory created! ✅

Multiple Cache Backends

Default + Sessions Cache

class MyConfig(DjangoConfig):
secret_key: str = "your-secret-key"
debug: bool = False

# Default cache for application data
cache_default: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/0",
timeout=300,
key_prefix="myapp"
)

# Separate cache for sessions
cache_sessions: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/1", # Different DB
timeout=86400, # 24 hours
key_prefix="sessions"
)

Generated Django settings:

CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://localhost:6379/0',
'TIMEOUT': 300,
'KEY_PREFIX': 'myapp',
'VERSION': 1,
'OPTIONS': {
'CONNECTION_POOL_KWARGS': {'max_connections': 50}
}
},
'sessions': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://localhost:6379/1',
'TIMEOUT': 86400,
'KEY_PREFIX': 'sessions',
'VERSION': 1,
'OPTIONS': {
'CONNECTION_POOL_KWARGS': {'max_connections': 50}
}
}
}

# Sessions backend
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'sessions'

Advanced Redis Configuration

Connection Pool Settings

class MyConfig(DjangoConfig):
secret_key: str = "your-secret-key"
debug: bool = False

cache_default: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/0",
max_connections=100,
connection_pool_kwargs={
'socket_connect_timeout': 5,
'socket_timeout': 5,
'retry_on_timeout': True,
'max_connections': 100,
'socket_keepalive': True,
'socket_keepalive_options': {
1: 1, # TCP_KEEPIDLE
2: 1, # TCP_KEEPINTVL
3: 3, # TCP_KEEPCNT
}
}
)

Redis Sentinel

class MyConfig(DjangoConfig):
secret_key: str = "your-secret-key"
debug: bool = False

cache_default: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/0",
connection_pool_kwargs={
'sentinels': [
('sentinel1.example.com', 26379),
('sentinel2.example.com', 26379),
('sentinel3.example.com', 26379),
],
'service_name': 'mymaster',
'sentinel_kwargs': {'password': 'sentinel_password'},
}
)

Redis Cluster

class MyConfig(DjangoConfig):
secret_key: str = "your-secret-key"
debug: bool = False

cache_default: CacheConfig = CacheConfig(
redis_url="redis://node1:6379/0",
connection_pool_kwargs={
'startup_nodes': [
{'host': 'node1.example.com', 'port': 6379},
{'host': 'node2.example.com', 'port': 6379},
{'host': 'node3.example.com', 'port': 6379},
],
'skip_full_coverage_check': True,
}
)

Environment-Specific Configuration

Using Properties

import os

class MyConfig(DjangoConfig):
secret_key: str = "your-secret-key"

@property
def cache_default(self) -> Optional[CacheConfig]:
if self._environment == "production":
return CacheConfig(
redis_url=os.getenv('REDIS_URL'),
timeout=600,
key_prefix="prod",
max_connections=200
)
elif self._environment == "development":
return CacheConfig(
# No redis_url - uses LocMemCache
timeout=60,
key_prefix="dev"
)
return None # Dummy cache

Using YAML

# config.production.yaml
cache_default:
redis_url: "redis://prod-cache.example.com:6379/0"
timeout: 600
key_prefix: "prod"
max_connections: 200

# config.development.yaml
cache_default:
timeout: 60
key_prefix: "dev"
# No redis_url - auto-selects LocMemCache

Cache Key Versioning

class MyConfig(DjangoConfig):
secret_key: str = "your-secret-key"
debug: bool = False

cache_default: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/0",
key_prefix="myapp",
version=2 # Increment when cache schema changes
)

Usage:

from django.core.cache import cache

# Set with version
cache.set('my_key', 'value', version=2)

# Get with version
value = cache.get('my_key', version=2)

# Different version = cache miss
value = cache.get('my_key', version=1) # None

Performance Tuning

Timeout Settings

class MyConfig(DjangoConfig):
cache_default: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/0",
timeout=300, # 5 minutes default
)

Common timeouts:

  • 60s - Frequently changing data
  • 300s (5m) - Default for most data
  • 3600s (1h) - Semi-static data
  • 86400s (24h) - Very static data

Connection Pool Size

class MyConfig(DjangoConfig):
cache_default: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/0",
max_connections=50, # Adjust based on load
)

Guidelines:

  • 10-20 - Low traffic (< 1000 req/min)
  • 50-100 - Medium traffic (1000-10000 req/min)
  • 100-200 - High traffic (> 10000 req/min)

Security Best Practices

1. Use Environment Variables

import os

class MyConfig(DjangoConfig):
cache_default: CacheConfig = CacheConfig(
redis_url=os.getenv('REDIS_URL'),
key_prefix=os.getenv('CACHE_PREFIX', 'myapp')
)

2. Enable SSL/TLS

class MyConfig(DjangoConfig):
cache_default: CacheConfig = CacheConfig(
redis_url="rediss://cache.example.com:6380/0", # SSL
connection_pool_kwargs={
'ssl_cert_reqs': 'required'
}
)

3. Use Different Databases

class MyConfig(DjangoConfig):
cache_default: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/0" # DB 0 for cache
)

cache_sessions: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/1" # DB 1 for sessions
)

Troubleshooting

Redis Connection Errors

Error:

ConnectionError: Error connecting to Redis

Solution:

class MyConfig(DjangoConfig):
cache_default: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/0",
connection_pool_kwargs={
'socket_connect_timeout': 10,
'retry_on_timeout': True
}
)

Cache Key Too Long

Error:

ValueError: Cache key too long (max 250 chars)

Solution:

class MyConfig(DjangoConfig):
cache_default: CacheConfig = CacheConfig(
redis_url="redis://localhost:6379/0",
key_prefix="short" # Use shorter prefix
)

See Also