X-Git-Url: https://git.openstreetmap.org./osqa.git/blobdiff_plain/410bfa05ee36ed1d99356c443a5f3f6aa3ee9578..3ef231f42d6b4d94e7cad81053e29d2dc7e7a331:/forum/models/utils.py diff --git a/forum/models/utils.py b/forum/models/utils.py index 5ac8900..1fbda58 100644 --- a/forum/models/utils.py +++ b/forum/models/utils.py @@ -11,9 +11,13 @@ except ImportError: from copy import deepcopy from base64 import b64encode, b64decode from zlib import compress, decompress +import re +from base import BaseModel -class PickledObject(str): +MAX_MARKABLE_STRING_LENGTH = 100 + +class PickledObject(unicode): pass def dbsafe_encode(value, compress_object=True): @@ -33,6 +37,9 @@ def dbsafe_decode(value, compress_object=True): class PickledObjectField(models.Field): __metaclass__ = models.SubfieldBase + marker_re = re.compile(r'^T\[(?P\w+)\](?P.*)$', re.DOTALL) + markable_types = dict((t.__name__, t) for t in (str, int, unicode)) + def __init__(self, *args, **kwargs): self.compress = kwargs.pop('compress', True) self.protocol = kwargs.pop('protocol', 2) @@ -40,6 +47,20 @@ class PickledObjectField(models.Field): kwargs.setdefault('editable', False) super(PickledObjectField, self).__init__(*args, **kwargs) + def generate_type_marked_value(self, value): + return PickledObject(u"T[%s]%s" % (type(value).__name__, value)) + + def read_marked_value(self, value): + m = self.marker_re.match(value) + + if m: + marker = m.group('type') + value = m.group('value') + if marker in self.markable_types: + value = self.markable_types[marker](value) + + return value + def get_default(self): if self.has_default(): if callable(self.default): @@ -51,7 +72,10 @@ class PickledObjectField(models.Field): def to_python(self, value): if value is not None: try: - value = dbsafe_decode(value, self.compress) + if value.startswith("T["): + value = self.read_marked_value(value) + else: + value = dbsafe_decode(value, self.compress) except: if isinstance(value, PickledObject): raise @@ -59,7 +83,11 @@ class PickledObjectField(models.Field): def get_db_prep_value(self, value): if value is not None and not isinstance(value, PickledObject): - value = force_unicode(dbsafe_encode(value, self.compress)) + if type(value).__name__ in self.markable_types and not (isinstance(value, basestring) and len(value + ) > MAX_MARKABLE_STRING_LENGTH): + value = unicode(self.generate_type_marked_value(value)) + else: + value = unicode(dbsafe_encode(value, self.compress)) return value def value_to_string(self, obj): @@ -75,43 +103,26 @@ class PickledObjectField(models.Field): return super(PickledObjectField, self).get_db_prep_lookup(lookup_type, value) -class KeyValueManager(models.Manager): - - def create_cache_key(self, key): - return "%s:keyvalue:%s" % (settings.APP_URL, key) - - def save_to_cache(self, instance): - cache.set(self.create_cache_key(instance.key), instance, 2592000) - - def remove_from_cache(self, instance): - cache.delete(self.create_cache_key(instance.key)) - - def get(self, **kwargs): - if 'key' in kwargs: - instance = cache.get(self.create_cache_key(kwargs['key'])) - - if instance is None: - instance = super(KeyValueManager, self).get(**kwargs) - self.save_to_cache(instance) - - return instance - - else: - return super(KeyValueManager, self).get(**kwargs) - -class KeyValue(models.Model): +class KeyValue(BaseModel): key = models.CharField(max_length=255, unique=True) value = PickledObjectField() - objects = KeyValueManager() - class Meta: app_label = 'forum' - def save(self, *args, **kwargs): - super(KeyValue, self).save(*args, **kwargs) - KeyValue.objects.save_to_cache(self) + def cache_key(self): + return self._generate_cache_key(self.key) + + @classmethod + def infer_cache_key(cls, querydict): + try: + key = [v for (k, v) in querydict.items() if k in ('key', 'key__exact')][0] + + return cls._generate_cache_key(key) + except: + return None + + @classmethod + def value_to_list_on_cache_query(cls): + return 'key' - def delete(self): - KeyValue.objects.remove_from_cache(self) - super(KeyValue, self).delete()