Enabled database backend to properly require a cache backend that works in cross-process environments. This adds an optional setting CONSTANCE_DATABASE_CACHE_BACKEND.

This commit is contained in:
Jannis Leidel 2010-12-11 16:43:31 +01:00
parent 1dd0a8b7c9
commit 3ef39d9185
3 changed files with 50 additions and 16 deletions

View file

@ -82,8 +82,17 @@ configuration values:
pip install django-picklefield
The database backend will automatically cache the config values in memory
and clear them when when saving occurs.
The database backend has the ability to automatically cache the config
values and clear them when saving. You need to set the following setting
to enable this feature::
CONSTANCE_DATABASE_CACHE_BACKEND = 'memcached://127.0.0.1:11211/'
.. note::
This won't work with a cache backend that doesn't support
cross-process caching, because correct cache invalidation
can't be guaranteed.
.. _django-picklefield: http://pypi.python.org/pypi/django-picklefield/

View file

@ -1,37 +1,59 @@
from django.core.exceptions import ImproperlyConfigured
from django.db.models.signals import post_save
from django.utils.functional import memoize
from django.core.cache import get_cache
from django.core.cache.backends.locmem import CacheClass as LocMemCacheClass
from constance.backends import Backend
from constance import settings
db_cache = {}
db_cache = None
if settings.DATABASE_CACHE_BACKEND:
db_cache = get_cache(settings.DATABASE_CACHE_BACKEND)
if isinstance(db_cache, LocMemCacheClass):
raise ImproperlyConfigured(
"The CONSTANCE_DATABASE_CACHE_BACKEND setting refers to a "
"subclass of Django's local-memory backend (%r). Please set "
"it to a backend that supports cross-process caching."
% settings.DATABASE_CACHE_BACKEND)
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
if not self._model._meta.installed:
raise ImproperlyConfigured(
"The constance.backends.database app isn't installed "
"correctly. Make sure it's in your INSTALLED_APPS setting.")
# 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
def mget(self, keys):
for const in self._model._default_manager.filter(key__in=keys):
yield const.key, const.value
def get(self, key):
value = None
if db_cache:
value = db_cache.get(key)
if value is None:
try:
value = self._model._default_manager.get(key=key).value
except self._model.DoesNotExist:
pass
else:
if db_cache:
db_cache.add(key, value)
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})
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:
if db_cache and not created:
db_cache.clear()

View file

@ -17,3 +17,6 @@ CONNECTION_CLASS = getattr(settings, 'CONSTANCE_REDIS_CONNECTION_CLASS',
REDIS_CONNECTION = getattr(settings, 'CONSTANCE_REDIS_CONNECTION',
getattr(settings, 'CONSTANCE_CONNECTION', {}))
DATABASE_CACHE_BACKEND = getattr(settings, 'CONSTANCE_DATABASE_CACHE_BACKEND',
None)