Skip to content

Instantly share code, notes, and snippets.

@agrn
Last active August 29, 2015 14:26
Show Gist options
  • Save agrn/0dfd76153ba36f41cfef to your computer and use it in GitHub Desktop.
Save agrn/0dfd76153ba36f41cfef to your computer and use it in GitHub Desktop.
Redis cache backend for Django
# Copyright (c) 2015, Alban Gruin <[email protected]>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"Redis cache backend"
from django.core.cache.backends.base import DEFAULT_TIMEOUT, BaseCache
import redis
class RedisCache(BaseCache):
def __init__(self, server, params):
super(RedisCache, self).__init__(params)
self._server = params.get('LOCATION', 'localhost')
self._port = params.get('PORT', 6379)
self._db = params.get('DB', 0)
self._password = params.get('PASSWORD', None)
self._unixSocket = self._server.startswith('unix:/')
if self._unixSocket:
self._server = self._server[5:]
def __contains__(self, key):
return self.has_key(key)
@property
def _cache(self):
if not hasattr(self, '_client'):
if self._unixSocket:
self._client = redis.StrictRedis(unix_socket_path=self._server,
db=self._db,
password=self._password)
else:
self._client = redis.StrictRedis(host=self._server,
port=self._port, db=self._db,
password=self._password)
return self._client
def add(self, key, value, timeout=DEFAULT_TIMEOUT, *args, **kwargs):
if hasattr(value, '__len__') and len(value) <= 0:
return True
pipe = self._cache.pipeline()
if isinstance(value, list):
pipe.rpush(key, *value)
elif isinstance(value, dict):
pipe.hmset(key, value)
else:
pipe.set(key, value)
pipe.expire(key, timeout)
if pipe.execute() == [True, True]:
return True
else:
return False
def clear(self):
self._cache.flushdb()
def close(self):
if getattr(self, '_client', None) is not None:
del self._client
def decr(self, key, delta=1, *args, **kwargs):
return self._cache.decrby(key, -delta)
def delete(self, key, *args, **kwargs):
self._cache.delete(key)
def delete_many(self, keys, *args, **kwargs):
for key in keys:
self.delete(key, *args, **kwargs)
def get(self, key, default=None):
if self._cache.exists(key):
if self._cache.type(key) == 'string':
return self._cache.get(key)
elif self._cache.type(key) == 'list':
return self._cache.lrange(key, 0, -1)
elif self._cache.type(key) == 'hash':
return self._cache.hgetall(key)
else:
return default
def get_many(self, keys, *args, **kwargs):
return dict(zip(keys, [self.get(key) for key in keys]))
def get_or_set(self, key, default=None, timeout=DEFAULT_TIMEOUT, *args,
**kwargs):
if default is None:
raise ValueError('You need to specify a value.')
if self.has_key(key):
return self.get(key)
else:
if callable(default):
default = default()
if self.add(key, default, timeout, *args, **kwargs):
return self.get(key, *args, **kwargs)
return False
def has_key(self, key, *args, **kwargs):
return self._cache.exists(key)
def incr(self, key, delta=1, *args, **kwargs):
return self._cache.incrby(key, delta)
def set(self, key, value, timeout=DEFAULT_TIMEOUT, *args, **kwargs):
return self.add(key, value, timeout)
def set_many(self, data, timeout=DEFAULT_TIMEOUT, *args, **kwargs):
for key, value in data.items():
self.set(key, value, timeout, *args, **kwargs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment