1 from django.db import models
2 from django.core.cache import cache
3 from django.conf import settings
4 from django.utils.encoding import force_unicode
7 from cPickle import loads, dumps
9 from pickle import loads, dumps
11 from copy import deepcopy
12 from base64 import b64encode, b64decode
13 from zlib import compress, decompress
16 class PickledObject(str):
19 def dbsafe_encode(value, compress_object=True):
20 if not compress_object:
21 value = b64encode(dumps(deepcopy(value)))
23 value = b64encode(compress(dumps(deepcopy(value))))
24 return PickledObject(value)
26 def dbsafe_decode(value, compress_object=True):
27 if not compress_object:
28 value = loads(b64decode(value))
30 value = loads(decompress(b64decode(value)))
33 class PickledObjectField(models.Field):
34 __metaclass__ = models.SubfieldBase
36 def __init__(self, *args, **kwargs):
37 self.compress = kwargs.pop('compress', True)
38 self.protocol = kwargs.pop('protocol', 2)
39 kwargs.setdefault('null', True)
40 kwargs.setdefault('editable', False)
41 super(PickledObjectField, self).__init__(*args, **kwargs)
43 def get_default(self):
44 if self.has_default():
45 if callable(self.default):
49 return super(PickledObjectField, self).get_default()
51 def to_python(self, value):
54 value = dbsafe_decode(value, self.compress)
56 if isinstance(value, PickledObject):
60 def get_db_prep_value(self, value):
61 if value is not None and not isinstance(value, PickledObject):
62 value = force_unicode(dbsafe_encode(value, self.compress))
65 def value_to_string(self, obj):
66 value = self._get_val_from_obj(obj)
67 return self.get_db_prep_value(value)
69 def get_internal_type(self):
72 def get_db_prep_lookup(self, lookup_type, value):
73 if lookup_type not in ['exact', 'in', 'isnull']:
74 raise TypeError('Lookup type %s is not supported.' % lookup_type)
75 return super(PickledObjectField, self).get_db_prep_lookup(lookup_type, value)
78 class KeyValueManager(models.Manager):
80 def create_cache_key(self, key):
81 return "%s:keyvalue:%s" % (settings.APP_URL, key)
83 def save_to_cache(self, instance):
84 cache.set(self.create_cache_key(instance.key), instance, 2592000)
86 def remove_from_cache(self, instance):
87 cache.delete(self.create_cache_key(instance.key))
89 def get(self, **kwargs):
91 instance = cache.get(self.create_cache_key(kwargs['key']))
94 instance = super(KeyValueManager, self).get(**kwargs)
95 self.save_to_cache(instance)
100 return super(KeyValueManager, self).get(**kwargs)
102 class KeyValue(models.Model):
103 key = models.CharField(max_length=255, unique=True)
104 value = PickledObjectField()
106 objects = KeyValueManager()
111 def save(self, *args, **kwargs):
112 super(KeyValue, self).save(*args, **kwargs)
113 KeyValue.objects.save_to_cache(self)
116 KeyValue.objects.remove_from_cache(self)
117 super(KeyValue, self).delete()