public
Last active

A redis backend for Django Sessions, tested on Django 1.3+

  • Download Gist
redis_session_backend.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
from django.contrib.sessions.backends.base import SessionBase, CreateError
from django.conf import settings
from django.utils.encoding import force_unicode
import redis
 
class SessionStore(SessionBase):
""" Redis store for sessions"""
 
def __init__(self, session_key=None):
self.redis = redis.Redis(
host = settings.SESSION_REDIS_HOST,
port = settings.SESSION_REDIS_PORT,
socket_timeout = settings.REDIS_SOCKET_TIMEOUT
)
super(SessionStore, self).__init__(session_key)
 
@classmethod
def _get_key_for_redis(self, session_key):
return 'sessionstore:%s' % session_key
 
def _redis_key(self):
return self.__class__._get_key_for_redis(self.session_key)
 
def load(self):
session_data = self.redis.get(self._redis_key())
if session_data is not None:
return self.decode(force_unicode(session_data))
else:
self.create()
return {}
 
def create(self):
max_attempts = 10
attempt = 0
while True:
self.session_key = self._get_new_session_key()
session_dict = self._get_session(no_load = True)
session_data = self.encode(session_dict)
 
was_created = self.redis.setnx(self._redis_key(),
session_data)
if was_created:
self.redis.expire(self._redis_key(),
settings.SESSION_COOKIE_AGE)
self.modified = True
self._session_cache = session_dict
return
else:
# extremely unlikely
if attempt == max_attempts:
raise CreateError
else:
attempt += 1
continue
 
def save(self, must_create=False):
if must_create:
self.create()
else:
encoded_data = self.encode(self._session)
self.redis.setex(self._redis_key(), encoded_data, settings.SESSION_COOKIE_AGE)
 
def exists(self, session_key):
return self.redis.exists(self.__class__._get_key_for_redis(session_key))
 
def delete(self, session_key=None):
to_delete = (session_key or self.session_key)
redis_key = self.__class__._get_key_for_redis(to_delete)
self.redis.delete(redis_key)

Hello Mike,

I am testing your session backend but I am receiving the following error:

AttributeError at /directlogin/
can't set attribute

You have idea what can cause this?

Best Regards

We are testing your backend for session data, with the intent of using multiple redis servers in a replicated environment. Any hints would be appreciated.

you should get the below block out from the class's init to avoid calling it every time it is instantiated...to be called only one time.

self.redis = redis.Redis(
host = settings.SESSION_REDIS_HOST,
port = settings.SESSION_REDIS_PORT,
socket_timeout = settings.REDIS_SOCKET_TIMEOUT
)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.