Commits

Tim Savage  committed 9d323a3

Added cache key generation utils and associated tests

  • Participants
  • Parent commits 38a1cbc

Comments (0)

Files changed (4)

File django_extras/tests/__init__.py

 from django_extras.tests.forms.fields import *
 from django_extras.tests.http.responses import *
 from django_extras.tests.middleware.timing import *
+from django_extras.tests.utils.cache import *

File django_extras/tests/utils/__init__.py

Empty file added.

File django_extras/tests/utils/cache.py

+from django import test
+from django.db import models
+from django_extras.utils.cache import generate_key, instance_key
+
+
+class TestModel(models.Model):
+    name = models.CharField(max_length=10)
+
+    class Meta:
+        app_label = 'test'
+
+
+class GenerateKeyTestCase(test.TestCase):
+    def __init__(self, *args, **kwargs):
+        super(GenerateKeyTestCase, self).__init__(*args, **kwargs)
+        self.m = TestModel(id=1, name='eek')
+
+    def test_type_using_pk(self):
+        actual = generate_key(TestModel, pk=1)
+        self.assertEqual(actual, 'model:test.testmodel[pk=1]')
+
+    def test_type_using_knowen_field(self):
+        actual = generate_key(TestModel, id=2)
+        self.assertEqual(actual, 'model:test.testmodel[id=2]')
+
+    def test_type_using_unknown_field(self):
+        self.assertRaises(AttributeError, lambda : generate_key(TestModel, eek=2))
+
+    def test_type_using_single_postfix(self):
+        actual = generate_key(TestModel, 'cover', pk=1)
+        self.assertEqual(actual, 'model:test.testmodel[pk=1]:cover')
+
+    def test_type_using_multiple_postfix(self):
+        actual = generate_key(TestModel, 'foo', 'bar', pk=1)
+        self.assertEqual(actual, 'model:test.testmodel[pk=1]:foo-bar')
+
+    def test_instance_using_pk(self):
+        actual = generate_key(self.m, pk=1)
+        self.assertEqual(actual, 'model:test.testmodel[pk=1]')
+
+    def test_instance_using_known_field(self):
+        actual = generate_key(self.m, id=2)
+        self.assertEqual(actual, 'model:test.testmodel[id=2]')
+
+    def test_instance_using_unknown_field(self):
+        self.assertRaises(AttributeError, lambda : generate_key(self.m, eek=2))
+
+    def test_instance_using_single_postfix(self):
+        actual = generate_key(self.m, 'cover', pk=1)
+        self.assertEqual(actual, 'model:test.testmodel[pk=1]:cover')
+
+    def test_instance_using_multiple_postfix(self):
+        actual = generate_key(self.m, 'foo', 'bar', pk=1)
+        self.assertEqual(actual, 'model:test.testmodel[pk=1]:foo-bar')
+
+
+class InstanceKeyTestCase(test.TestCase):
+    def __init__(self, *args, **kwargs):
+        super(InstanceKeyTestCase, self).__init__(*args, **kwargs)
+        self.m = TestModel(id=1, name='eek')
+
+    def test_just_instance(self):
+        actual = instance_key(self.m)
+        self.assertEqual(actual, 'model:test.testmodel[pk=1]')
+
+    def test_specific_fields(self):
+        actual = instance_key(self.m, ('name', ))
+        self.assertEqual(actual, 'model:test.testmodel[name=eek]')
+
+    def test_unknown_field(self):
+        self.assertRaises(AttributeError, lambda : instance_key(self.m, ('eek', )))
+
+    def test_postfix(self):
+        actual = instance_key(self.m, ('name', ), 'cover')
+        self.assertEqual(actual, 'model:test.testmodel[name=eek]:cover')

File django_extras/utils/cache.py

+# -*- coding:utf8 -*-
+__all__ = ('generate_key', 'instance_key')
+
+
+def _generate_key(instance_or_type, values, postfix=None):
+    opts = instance_or_type._meta
+    key = 'model:%s.%s[%s]' % (
+        opts.app_label, opts.module_name,
+        ','.join(['%s=%s' % v for v in values])
+    )
+    if postfix:
+        key += ':' + postfix
+    return key
+
+def generate_key(instance_or_type, *args, **kwargs):
+    """
+    Generate a cache/no-sql key based from a model instance or type.
+
+    Any key/value is used to indicate a field parameter.
+    """
+    field_names = [f.name for f in instance_or_type._meta.fields]
+    field_names.append('pk')
+    for field in kwargs.iterkeys():
+        if field not in field_names:
+            raise AttributeError('Model "%s" has no field "%s".' % (instance_or_type._meta.module_name, field))
+    return _generate_key(instance_or_type, kwargs.items(), '-'.join(args))
+
+def instance_key(instance, fields=None, postfix=None):
+    """
+    Generate a cache/no-sql key based from a model instance.
+
+    Fields can be used to generate a key not based on a private key.
+    """
+    if fields:
+        values = [(f, getattr(instance, f)) for f in fields]
+    else:
+        values = [('pk', instance.pk),]
+    return _generate_key(instance, values, postfix)