mirror of
https://github.com/jazzband/django-constance.git
synced 2026-03-16 22:40:24 +00:00
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:
parent
eea0d2fdf9
commit
82e19cec9f
10 changed files with 123 additions and 119 deletions
|
|
@ -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))
|
||||
|
||||
16
constance/backends/__init__.py
Normal file
16
constance/backends/__init__.py
Normal 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
|
||||
|
||||
37
constance/backends/database/__init__.py
Normal file
37
constance/backends/database/__init__.py
Normal 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()
|
||||
20
constance/backends/database/models.py
Normal file
20
constance/backends/database/models.py
Normal 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'
|
||||
29
constance/backends/redis.py
Normal file
29
constance/backends/redis.py
Normal 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))
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
|
|
@ -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', {}))
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ INSTALLED_APPS = (
|
|||
'django.contrib.admin',
|
||||
|
||||
'constance',
|
||||
'constance.backends.database',
|
||||
|
||||
'testproject.test_app',
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue