]> git.openstreetmap.org Git - osqa.git/blob - forum/models/utils.py
Converted the new question notification template.
[osqa.git] / forum / models / utils.py
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
5
6 try:
7     from cPickle import loads, dumps
8 except ImportError:
9     from pickle import loads, dumps
10
11 from copy import deepcopy
12 from base64 import b64encode, b64decode
13 from zlib import compress, decompress
14
15
16 class PickledObject(str):
17     pass
18
19 def dbsafe_encode(value, compress_object=True):
20     if not compress_object:
21         value = b64encode(dumps(deepcopy(value)))
22     else:
23         value = b64encode(compress(dumps(deepcopy(value))))
24     return PickledObject(value)
25
26 def dbsafe_decode(value, compress_object=True):
27     if not compress_object:
28         value = loads(b64decode(value))
29     else:
30         value = loads(decompress(b64decode(value)))
31     return value
32
33 class PickledObjectField(models.Field):
34     __metaclass__ = models.SubfieldBase
35
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)
42
43     def get_default(self):
44         if self.has_default():
45             if callable(self.default):
46                 return self.default()
47             return self.default
48
49         return super(PickledObjectField, self).get_default()
50
51     def to_python(self, value):
52         if value is not None:
53             try:
54                 value = dbsafe_decode(value, self.compress)
55             except:
56                 if isinstance(value, PickledObject):
57                     raise
58         return value
59
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))
63         return value
64
65     def value_to_string(self, obj):
66         value = self._get_val_from_obj(obj)
67         return self.get_db_prep_value(value)
68
69     def get_internal_type(self):
70         return 'TextField'
71
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)
76
77
78 class KeyValueManager(models.Manager):
79
80     def create_cache_key(self, key):
81         return "%s:keyvalue:%s" % (settings.APP_URL, key)
82
83     def save_to_cache(self, instance):
84         cache.set(self.create_cache_key(instance.key), instance, 2592000)
85
86     def remove_from_cache(self, instance):
87         cache.delete(self.create_cache_key(instance.key))
88
89     def get(self, **kwargs):
90         if 'key' in kwargs:
91             instance = cache.get(self.create_cache_key(kwargs['key']))
92
93             if instance is None:
94                 instance = super(KeyValueManager, self).get(**kwargs)
95                 self.save_to_cache(instance)
96
97             return instance
98
99         else:
100             return super(KeyValueManager, self).get(**kwargs)
101
102 class KeyValue(models.Model):
103     key = models.CharField(max_length=255, unique=True)
104     value = PickledObjectField()
105
106     objects = KeyValueManager()
107
108     class Meta:
109         app_label = 'forum'
110
111     def save(self, *args, **kwargs):
112         super(KeyValue, self).save(*args, **kwargs)
113         KeyValue.objects.save_to_cache(self)
114
115     def delete(self):
116         KeyValue.objects.remove_from_cache(self)
117         super(KeyValue, self).delete()