Refactored backend system slightly to have a nicer directory structure. Using the database backend now only requires to add 'constance.backends.database' to INSTALLED_APPS and setting CONSTANCE_BACKEND to 'constance.backends.database.DatabaseBackend'. Also reverted default backend to being the Redis backend.

This commit is contained in:
Jannis Leidel 2010-12-01 18:13:37 +01:00
parent eea0d2fdf9
commit 82e19cec9f
10 changed files with 123 additions and 119 deletions

View file

@ -1,84 +0,0 @@
from django.core.exceptions import ImproperlyConfigured
from django.db.models.signals import post_save
from django.utils.functional import memoize
from constance import settings
from constance.utils import import_module_attr
try:
from cPickle import loads, dumps
except ImportError:
from pickle import loads, dumps
class Backend(object):
def __init__(self, prefix):
self._prefix = prefix
def get(self, key):
"""
Get the key from the backend store and return it.
Return None if not found.
"""
raise NotImplementedError
def set(self, key, value):
"""
Add the value to the backend store given the key.
"""
raise NotImplementedError
db_cache = {}
class DatabaseBackend(Backend):
def __init__(self, prefix):
super(DatabaseBackend, self).__init__(prefix)
from constance.models import Constance
if not Constance._meta.installed:
raise ImproperlyConfigured(
"The constance app isn't installed correctly. "
"Make sure it's listed in the INSTALLED_APPS setting.")
self._model = Constance
# Clear simple cache.
post_save.connect(self.clear, sender=self._model)
def _get(self, key):
try:
value = self._model._default_manager.get(key=key).value
except self._model.DoesNotExist:
return None
return value
get = memoize(_get, db_cache, 2)
def set(self, key, value):
constance, created = self._model._default_manager.get_or_create(key=key, defaults={'value': value})
if not created:
constance.value = value
constance.save()
def clear(self, sender, instance, created, **kwargs):
if not created:
db_cache.clear()
class RedisBackend(Backend):
def __init__(self, prefix):
super(RedisBackend, self).__init__(prefix)
connection_cls = settings.CONNECTION_CLASS
if connection_cls is not None:
self._rd = import_module_attr(connection_cls)()
else:
import redis
self._rd = redis.Redis(**settings.REDIS_CONNECTION)
def get(self, key):
value = self._rd.get("%s%s" % (self._prefix, key))
if value:
return loads(value)
return None
def set(self, key, value):
self._rd.set("%s%s" % (self._prefix, key), dumps(value))

View file

@ -0,0 +1,16 @@
class Backend(object):
def get(self, key):
"""
Get the key from the backend store and return it.
Return None if not found.
"""
raise NotImplementedError
def set(self, key, value):
"""
Add the value to the backend store given the key.
"""
raise NotImplementedError

View file

@ -0,0 +1,37 @@
from django.core.exceptions import ImproperlyConfigured
from django.db.models.signals import post_save
from django.utils.functional import memoize
from constance.backends import Backend
db_cache = {}
class DatabaseBackend(Backend):
def __init__(self):
from constance.backends.database.models import Constance
if not Constance._meta.installed:
raise ImproperlyConfigured(
"The constance.contrib.database app isn't installed correctly. "
"Make sure it's listed in the INSTALLED_APPS setting.")
self._model = Constance
# Clear simple cache.
post_save.connect(self.clear, sender=self._model)
def _get(self, key):
try:
value = self._model._default_manager.get(key=key).value
except self._model.DoesNotExist:
return None
return value
get = memoize(_get, db_cache, 2)
def set(self, key, value):
constance, created = self._model._default_manager.get_or_create(key=key, defaults={'value': value})
if not created:
constance.value = value
constance.save()
def clear(self, sender, instance, created, **kwargs):
if not created:
db_cache.clear()

View file

@ -0,0 +1,20 @@
from django.db import models
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ugettext_lazy as _
try:
from picklefield import PickledObjectField
except ImportError:
raise ImproperlyConfigured("Couldn't find the the 3rd party app "
"django-picklefield which is required for "
"the constance database backend.")
class Constance(models.Model):
key = models.TextField()
value = PickledObjectField()
class Meta:
verbose_name = _('constance')
verbose_name_plural = _('constances')
db_table = 'constance_config'

View file

@ -0,0 +1,29 @@
from constance import settings, utils
from constance.backends import Backend
try:
from cPickle import loads, dumps
except ImportError:
from pickle import loads, dumps
class RedisBackend(Backend):
def __init__(self):
super(RedisBackend, self).__init__()
self._prefix = settings.PREFIX
connection_cls = settings.CONNECTION_CLASS
if connection_cls is not None:
self._rd = utils.import_module_attr(connection_cls)()
else:
import redis
self._rd = redis.Redis(**settings.REDIS_CONNECTION)
def get(self, key):
value = self._rd.get("%s%s" % (self._prefix, key))
if value:
return loads(value)
return None
def set(self, key, value):
self._rd.set("%s%s" % (self._prefix, key), dumps(value))

View file

@ -1,18 +1,17 @@
from constance import settings
from constance.utils import import_module_attr
from constance import settings, utils
class Config(object):
"""
The global config wrapper that handles the backend.
"""
def __init__(self):
super(Config, self).__setattr__(
'_backend', import_module_attr(settings.BACKEND)(settings.PREFIX))
super(Config, self).__setattr__('_backend',
utils.import_module_attr(settings.BACKEND)())
def __getattr__(self, key):
try:
default, help_text = settings.CONFIG[key]
except KeyError, e:
except KeyError:
raise AttributeError(key)
result = self._backend.get(key)
if result is None:

View file

@ -1,25 +0,0 @@
from constance import settings
if settings.BACKEND == 'constance.backends.DatabaseBackend':
from django.db import models
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ugettext_lazy as _
try:
from picklefield import PickledObjectField
except ImportError:
raise ImproperlyConfigured("Couldn't find the the 3rd party app "
"django-picklefield which is required for "
"the constance database backend.")
class Constance(models.Model):
key = models.TextField()
value = PickledObjectField()
class Meta:
verbose_name = _('constance')
verbose_name_plural = _('constances')
db_table = 'constance_config'

View file

@ -5,13 +5,15 @@ settings = import_module_attr(
os.getenv('CONSTANCE_SETTINGS_MODULE', 'django.conf.settings')
)
PREFIX = getattr(settings, 'CONSTANCE_PREFIX', 'constance:')
PREFIX = getattr(settings, 'CONSTANCE_REDIS_PREFIX',
getattr(settings, 'CONSTANCE_PREFIX', 'constance:'))
BACKEND = getattr(settings, 'CONSTANCE_BACKEND', 'constance.backends.DatabaseBackend')
BACKEND = getattr(settings, 'CONSTANCE_BACKEND', 'constance.backends.redis.RedisBackend')
CONFIG = getattr(settings, 'CONSTANCE_CONFIG', {})
CONNECTION_CLASS = getattr(settings, 'CONSTANCE_CONNECTION_CLASS', None)
CONNECTION_CLASS = getattr(settings, 'CONSTANCE_REDIS_CONNECTION_CLASS',
getattr(settings, 'CONSTANCE_CONNECTION_CLASS', None))
REDIS_CONNECTION = getattr(settings, 'CONSTANCE_REDIS_CONNECTION',
getattr(settings, 'CONSTANCE_CONNECTION', {}))

View file

@ -16,6 +16,7 @@ INSTALLED_APPS = (
'django.contrib.admin',
'constance',
'constance.backends.database',
'testproject.test_app',
)

View file

@ -75,7 +75,7 @@ class TestRedis(TestCase, TestStorage):
def setUp(self):
self.old_backend = settings.BACKEND
settings.BACKEND = 'constance.backends.RedisBackend'
settings.BACKEND = 'constance.backends.redis.RedisBackend'
def tearDown(self):
del sys.modules['constance']
@ -86,7 +86,16 @@ class TestRedis(TestCase, TestStorage):
constance.config = Config()
class TestDatabase(TestCase, TestStorage):
pass
def setUp(self):
self.old_backend = settings.BACKEND
settings.BACKEND = 'constance.backends.database.DatabaseBackend'
def tearDown(self):
del sys.modules['constance']
settings.BACKEND = self.old_backend
import constance
constance.config = Config()
class TestAdmin(TestCase):
model = Config