Created
November 4, 2011 20:13
-
-
Save mattwilliamson/1340368 to your computer and use it in GitHub Desktop.
Metaclass Django Model Instance Caching
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
import uuid | |
import re | |
from decimal import Decimal | |
from django.conf import settings | |
from django.db import models | |
from django.db.models import signals | |
from django.dispatch import receiver | |
from django.core.cache import cache | |
def post_save_cache(sender, instance, signal, *args, **kwargs): | |
"""This is called when any BaseModel subclass instance is saved. Then we cache the instance.""" | |
logging.debug('Saving %s instance to cache.' % instance.__class__.__name__) | |
# Store full instance under SID-based Key | |
cache.set(instance.get_cache_key_sid(instance.sid), instance, settings.DEFAULT_INSTANCE_CACHE_TIME) | |
# Store SID under PK-based key | |
cache.set(instance.get_cache_key_pk(instance.pk), instance, settings.DEFAULT_INSTANCE_CACHE_TIME) | |
class InstanceCachable(models.Model.__metaclass__): | |
"""Meta class for Models. | |
Used to setup post/pre-save signals for caching all models that inherit from BaseModel""" | |
def __init__(cls, name, bases, dct): | |
super(InstanceCachable, cls).__init__(name, bases, dct) | |
signals.post_save.connect(post_save_cache, sender=cls) | |
class BaseModel(models.Model): | |
"""Contains some basic fields for most models to contain""" | |
__metaclass__ = InstanceCachable | |
class Meta: | |
abstract = True | |
ordering = ('-date_created',) | |
sid_prefix = '' | |
date_created = models.DateTimeField(blank=True, null=True, auto_now_add=True) | |
date_updated = models.DateTimeField(blank=True, null=True, auto_now=True) | |
sid = models.CharField(max_length=34, db_index=True, unique=True, blank=True, null=True) | |
friendly_name = models.CharField(max_length=64, blank=True, default='') | |
def __unicode__(self): | |
return self.friendly_name or self.sid | |
def generate_sid(self): | |
self.sid = str(getattr(self, 'sid_prefix', self.__class__.__name__))[:2] + uuid.uuid4().hex | |
def save(self, *args, **kwargs): | |
if self.sid in ('', None): | |
self.generate_sid() | |
super(BaseModel, self).save(*args, **kwargs) | |
@classmethod | |
def get_by_sid(cls, sid): | |
return cls.object.get(sid=sid) | |
@classmethod | |
def get_cache_key_sid(cls, sid): | |
"""Returns a string used as a caching key. SID-based.""" | |
return 'Instance.sid.%s.%s' % (cls.__name__, sid) | |
@classmethod | |
def get_cache_key_pk(cls, pk): | |
"""Returns a string used as a caching key. Primary key-based.""" | |
return 'Instance.pk.%s.%s' % (cls.__name__, pk) | |
@classmethod | |
def get_by_sid(cls, sid): | |
logging.debug('Fetching %s from cache with sid "%s"' % (cls.__name__, sid)) | |
key = cls.get_cache_key_sid(sid) | |
instance = cache.get() | |
# If not in the cache, fetch from db and put into cache | |
if not instance: | |
logging.debug('Not in cache. Fetching from DB.') | |
instance = cls.objects.get(sid=sid) | |
post_save_cache(cls, instance, signals.post_save) | |
return instance | |
@classmethod | |
def get_by_pk(cls, pk): | |
logging.debug('Fetching %s from cache with primary key "%s"' % (cls.__name__, pk)) | |
key = cls.get_cache_key_pk(pk) | |
instance = cache.get() | |
# If not in the cache, fetch from db and put into cache | |
if not instance: | |
logging.debug('Not in cache. Fetching from DB.') | |
instance = cls.objects.get(pk=pk) | |
post_save_cache(cls, instance, signals.post_save) | |
return instance |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment