python / expert
Snippet
Django Custom Cache Backend with Database Storage and Versioning
This snippet implements a custom Django cache backend storing data in the database. Extending `BaseCache`, it implements required methods with database-backed storage, automatic key versioning, and expiration handling. This pattern is valuable for deployments where Redis/Memcached are unavailable, offering TTL-based expiration with atomic transactions.
snippet.py
python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from django.core.cache.backends.base import BaseCachefrom django.db import transactionfrom myapp.models import CacheEntryclass DatabaseCacheBackend(BaseCache):def __init__(self, params):super().__init__(params)self.version = params.get('VERSION', 1)def make_key(self, key, version=None):version = version or self.versionreturn f"cache:v{version}:{key}"def add(self, key, value, timeout=None):return self._set_or_get(key, value, timeout, add=True) is Nonedef _set_or_get(self, key, value=None, timeout=None, add=False):cache_key = self.make_key(key)expires_at = self._get_expires_at(timeout)try:with transaction.atomic():entry = CacheEntry.objects.filter(cache_key=cache_key).first()if entry:if add:return entryentry.value = self.serialize(value)entry.expires_at = expires_atentry.save()else:CacheEntry.objects.create(cache_key=cache_key,value=self.serialize(value),expires_at=expires_at)except Exception:return Nonereturn Nonedef get(self, key, default=None):cache_key = self.make_key(key)try:entry = CacheEntry.objects.get(cache_key=cache_key)if entry.is_expired:entry.delete()return defaultreturn self.deserialize(entry.value)except CacheEntry.DoesNotExist:return default
django
Breakdown
1
class DatabaseCacheBackend(BaseCache)
Custom cache backend extending Django's BaseCache abstract class
2
def make_key(self, key, version=None)
Generates versioned cache key with namespace prefix
3
def add(self, key, value, timeout=None)
Adds key only if not exists, returns boolean success
4
with transaction.atomic()
Ensures atomic read-modify-write operations for data integrity
5
def get(self, key, default=None)
Retrieves and deserializes cached value, handles expiration