Fixed #2066: session data can now be stored in the cache or on the filesystem. This should be fully backwards-compatible (the database cache store is still the default). A big thanks to John D'Agostino for the bulk of this code.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@6333 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
e6460e4134
commit
bcf7e9a9fe
1
AUTHORS
1
AUTHORS
|
@ -87,6 +87,7 @@ answer newbie questions, and generally made Django that much better:
|
|||
Matt Croydon <http://www.postneo.com/>
|
||||
flavio.curella@gmail.com
|
||||
Jure Cuhalev <gandalf@owca.info>
|
||||
John D'Agostino <john.dagostino@gmail.com>
|
||||
dackze+django@gmail.com
|
||||
David Danier <goliath.mailinglist@gmx.de>
|
||||
Dirk Datzert <dummy@habmalnefrage.de>
|
||||
|
|
|
@ -277,6 +277,8 @@ SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or No
|
|||
SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
|
||||
SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
|
||||
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.
|
||||
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # The module to store session data
|
||||
SESSION_FILE_PATH = '/tmp/' # Directory to store session files if using the file session module
|
||||
|
||||
#########
|
||||
# CACHE #
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
import base64
|
||||
import md5
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError:
|
||||
import pickle
|
||||
|
||||
class SessionBase(object):
|
||||
"""
|
||||
Base class for all Session classes.
|
||||
"""
|
||||
|
||||
TEST_COOKIE_NAME = 'testcookie'
|
||||
TEST_COOKIE_VALUE = 'worked'
|
||||
|
||||
def __init__(self, session_key=None):
|
||||
self._session_key = session_key
|
||||
self.accessed = False
|
||||
self.modified = False
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self._session
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._session[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._session[key] = value
|
||||
self.modified = True
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._session[key]
|
||||
self.modified = True
|
||||
|
||||
def keys(self):
|
||||
return self._session.keys()
|
||||
|
||||
def items(self):
|
||||
return self._session.items()
|
||||
|
||||
def get(self, key, default=None):
|
||||
return self._session.get(key, default)
|
||||
|
||||
def pop(self, key, *args):
|
||||
return self._session.pop(key, *args)
|
||||
|
||||
def set_test_cookie(self):
|
||||
self[self.TEST_COOKIE_NAME] = self.TEST_COOKIE_VALUE
|
||||
|
||||
def test_cookie_worked(self):
|
||||
return self.get(self.TEST_COOKIE_NAME) == self.TEST_COOKIE_VALUE
|
||||
|
||||
def delete_test_cookie(self):
|
||||
del self[self.TEST_COOKIE_NAME]
|
||||
|
||||
def encode(self, session_dict):
|
||||
"Returns the given session dictionary pickled and encoded as a string."
|
||||
pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
|
||||
pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
|
||||
return base64.encodestring(pickled + pickled_md5)
|
||||
|
||||
def decode(self, session_data):
|
||||
encoded_data = base64.decodestring(session_data)
|
||||
pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
|
||||
if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
|
||||
raise SuspiciousOperation("User tampered with session cookie.")
|
||||
try:
|
||||
return pickle.loads(pickled)
|
||||
# Unpickling can cause a variety of exceptions. If something happens,
|
||||
# just return an empty dictionary (an empty session).
|
||||
except:
|
||||
return {}
|
||||
|
||||
def _get_new_session_key(self):
|
||||
"Returns session key that isn't being used."
|
||||
# The random module is seeded when this Apache child is created.
|
||||
# Use settings.SECRET_KEY as added salt.
|
||||
while 1:
|
||||
session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1),
|
||||
os.getpid(), time.time(), settings.SECRET_KEY)).hexdigest()
|
||||
if not self.exists(session_key):
|
||||
break
|
||||
return session_key
|
||||
|
||||
def _get_session_key(self):
|
||||
if self._session_key:
|
||||
return self._session_key
|
||||
else:
|
||||
self._session_key = self._get_new_session_key()
|
||||
return self._session_key
|
||||
|
||||
def _set_session_key(self, session_key):
|
||||
self._session_key = session_key
|
||||
|
||||
session_key = property(_get_session_key, _set_session_key)
|
||||
|
||||
def _get_session(self):
|
||||
# Lazily loads session from storage.
|
||||
self.accessed = True
|
||||
try:
|
||||
return self._session_cache
|
||||
except AttributeError:
|
||||
if self.session_key is None:
|
||||
self._session_cache = {}
|
||||
else:
|
||||
self._session_cache = self.load()
|
||||
return self._session_cache
|
||||
|
||||
_session = property(_get_session)
|
||||
|
||||
# Methods that child classes must implement.
|
||||
|
||||
def exists(self, session_key):
|
||||
"""
|
||||
Returns True if the given session_key already exists.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
Saves the session data.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def delete(self, session_key):
|
||||
"""
|
||||
Clears out the session data under this key.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def load(self):
|
||||
"""
|
||||
Loads the session data and returns a dictionary.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
from django.conf import settings
|
||||
from django.contrib.sessions.backends.base import SessionBase
|
||||
from django.core.cache import cache
|
||||
|
||||
class SessionStore(SessionBase):
|
||||
"""
|
||||
A cache-based session store.
|
||||
"""
|
||||
def __init__(self, session_key=None):
|
||||
self._cache = cache
|
||||
super(SessionStore, self).__init__(session_key)
|
||||
|
||||
def load(self):
|
||||
session_data = self._cache.get(self.session_key)
|
||||
return session_data or {}
|
||||
|
||||
def save(self):
|
||||
self._cache.set(self.session_key, self._session, settings.SESSION_COOKIE_AGE)
|
||||
|
||||
def exists(self, session_key):
|
||||
if self._cache.get(session_key):
|
||||
return True
|
||||
return False
|
||||
|
||||
def delete(self, session_key):
|
||||
self._cache.delete(session_key)
|
|
@ -0,0 +1,49 @@
|
|||
from django.conf import settings
|
||||
from django.contrib.sessions.models import Session
|
||||
from django.contrib.sessions.backends.base import SessionBase
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
import datetime
|
||||
|
||||
class SessionStore(SessionBase):
|
||||
"""
|
||||
Implements database session store
|
||||
"""
|
||||
def __init__(self, session_key=None):
|
||||
super(SessionStore, self).__init__(session_key)
|
||||
|
||||
def load(self):
|
||||
try:
|
||||
s = Session.objects.get(
|
||||
session_key = self.session_key,
|
||||
expire_date__gt=datetime.datetime.now()
|
||||
)
|
||||
return self.decode(s.session_data)
|
||||
except (Session.DoesNotExist, SuspiciousOperation):
|
||||
|
||||
# Create a new session_key for extra security.
|
||||
self.session_key = self._get_new_session_key()
|
||||
self._session_cache = {}
|
||||
|
||||
# Save immediately to minimize collision
|
||||
self.save()
|
||||
return {}
|
||||
|
||||
def exists(self, session_key):
|
||||
try:
|
||||
Session.objects.get(session_key=session_key)
|
||||
except Session.DoesNotExist:
|
||||
return False
|
||||
return True
|
||||
|
||||
def save(self):
|
||||
Session.objects.create(
|
||||
session_key = self.session_key,
|
||||
session_data = self.encode(self._session),
|
||||
expire_date = datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE)
|
||||
)
|
||||
|
||||
def delete(self, session_key):
|
||||
try:
|
||||
Session.objects.get(session_key=session_key).delete()
|
||||
except Session.DoesNotExist:
|
||||
pass
|
|
@ -0,0 +1,67 @@
|
|||
import os
|
||||
from django.conf import settings
|
||||
from django.contrib.sessions.backends.base import SessionBase
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
|
||||
class SessionStore(SessionBase):
|
||||
"""
|
||||
Implements a file based session store.
|
||||
"""
|
||||
def __init__(self, session_key=None):
|
||||
self.storage_path = settings.SESSION_FILE_PATH
|
||||
self.file_prefix = settings.SESSION_COOKIE_NAME
|
||||
super(SessionStore, self).__init__(session_key)
|
||||
|
||||
def _key_to_file(self, session_key=None):
|
||||
"""
|
||||
Get the file associated with this session key.
|
||||
"""
|
||||
if session_key is None:
|
||||
session_key = self.session_key
|
||||
|
||||
# Make sure we're not vulnerable to directory traversal. Session keys
|
||||
# should always be md5s, so they should never contain directory components.
|
||||
if os.path.sep in session_key:
|
||||
raise SuspiciousOperation("Invalid characters (directory components) in session key")
|
||||
|
||||
return os.path.join(self.storage_path, self.file_prefix + session_key)
|
||||
|
||||
def load(self):
|
||||
session_data = {}
|
||||
try:
|
||||
session_file = open(self._key_to_file(), "rb")
|
||||
try:
|
||||
session_data = self.decode(session_file.read())
|
||||
except(EOFError, SuspiciousOperation):
|
||||
self._session_key = self._get_new_session_key()
|
||||
self._session_cache = {}
|
||||
self.save()
|
||||
finally:
|
||||
session_file.close()
|
||||
except(IOError):
|
||||
pass
|
||||
return session_data
|
||||
|
||||
def save(self):
|
||||
try:
|
||||
f = open(self._key_to_file(self.session_key), "wb")
|
||||
try:
|
||||
f.write(self.encode(self._session))
|
||||
finally:
|
||||
f.close()
|
||||
except(IOError, EOFError):
|
||||
pass
|
||||
|
||||
def exists(self, session_key):
|
||||
if os.path.exists(self._key_to_file(session_key)):
|
||||
return True
|
||||
return False
|
||||
|
||||
def delete(self, session_key):
|
||||
try:
|
||||
os.unlink(self._key_to_file(session_key))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def clean(self):
|
||||
pass
|
|
@ -1,6 +1,4 @@
|
|||
from django.conf import settings
|
||||
from django.contrib.sessions.models import Session
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
from django.utils.cache import patch_vary_headers
|
||||
from email.Utils import formatdate
|
||||
import datetime
|
||||
|
@ -9,73 +7,11 @@ import time
|
|||
TEST_COOKIE_NAME = 'testcookie'
|
||||
TEST_COOKIE_VALUE = 'worked'
|
||||
|
||||
class SessionWrapper(object):
|
||||
def __init__(self, session_key):
|
||||
self.session_key = session_key
|
||||
self.accessed = False
|
||||
self.modified = False
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self._session
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._session[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._session[key] = value
|
||||
self.modified = True
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._session[key]
|
||||
self.modified = True
|
||||
|
||||
def keys(self):
|
||||
return self._session.keys()
|
||||
|
||||
def items(self):
|
||||
return self._session.items()
|
||||
|
||||
def get(self, key, default=None):
|
||||
return self._session.get(key, default)
|
||||
|
||||
def pop(self, key, *args):
|
||||
self.modified = self.modified or key in self._session
|
||||
return self._session.pop(key, *args)
|
||||
|
||||
def set_test_cookie(self):
|
||||
self[TEST_COOKIE_NAME] = TEST_COOKIE_VALUE
|
||||
|
||||
def test_cookie_worked(self):
|
||||
return self.get(TEST_COOKIE_NAME) == TEST_COOKIE_VALUE
|
||||
|
||||
def delete_test_cookie(self):
|
||||
del self[TEST_COOKIE_NAME]
|
||||
|
||||
def _get_session(self):
|
||||
# Lazily loads session from storage.
|
||||
self.accessed = True
|
||||
try:
|
||||
return self._session_cache
|
||||
except AttributeError:
|
||||
if self.session_key is None:
|
||||
self._session_cache = {}
|
||||
else:
|
||||
try:
|
||||
s = Session.objects.get(session_key=self.session_key,
|
||||
expire_date__gt=datetime.datetime.now())
|
||||
self._session_cache = s.get_decoded()
|
||||
except (Session.DoesNotExist, SuspiciousOperation):
|
||||
self._session_cache = {}
|
||||
# Set the session_key to None to force creation of a new
|
||||
# key, for extra security.
|
||||
self.session_key = None
|
||||
return self._session_cache
|
||||
|
||||
_session = property(_get_session)
|
||||
|
||||
class SessionMiddleware(object):
|
||||
|
||||
def process_request(self, request):
|
||||
request.session = SessionWrapper(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None))
|
||||
engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
|
||||
request.session = engine.SessionStore(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None))
|
||||
|
||||
def process_response(self, request, response):
|
||||
# If request.session was modified, or if response.session was set, save
|
||||
|
@ -89,25 +25,22 @@ class SessionMiddleware(object):
|
|||
if accessed:
|
||||
patch_vary_headers(response, ('Cookie',))
|
||||
if modified or settings.SESSION_SAVE_EVERY_REQUEST:
|
||||
if request.session.session_key:
|
||||
session_key = request.session.session_key
|
||||
else:
|
||||
obj = Session.objects.get_new_session_object()
|
||||
session_key = obj.session_key
|
||||
|
||||
if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
|
||||
max_age = None
|
||||
expires = None
|
||||
else:
|
||||
max_age = settings.SESSION_COOKIE_AGE
|
||||
rfcdate = formatdate(time.time() + settings.SESSION_COOKIE_AGE)
|
||||
|
||||
# Fixed length date must have '-' separation in the format
|
||||
# DD-MMM-YYYY for compliance with Netscape cookie standard
|
||||
expires = (rfcdate[:7] + "-" + rfcdate[8:11]
|
||||
+ "-" + rfcdate[12:26] + "GMT")
|
||||
new_session = Session.objects.save(session_key, request.session._session,
|
||||
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
|
||||
response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,
|
||||
expires = datetime.datetime.strftime(datetime.datetime.utcnow() + \
|
||||
datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
|
||||
|
||||
# Save the seesion data and refresh the client cookie.
|
||||
request.session.save()
|
||||
response.set_cookie(settings.SESSION_COOKIE_NAME, request.session.session_key,
|
||||
max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
|
||||
secure=settings.SESSION_COOKIE_SECURE or None)
|
||||
|
||||
return response
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import base64, md5, random, sys, datetime, os, time
|
||||
import base64, md5, random, sys, datetime
|
||||
import cPickle as pickle
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -74,6 +74,7 @@ class Session(models.Model):
|
|||
session_data = models.TextField(_('session data'))
|
||||
expire_date = models.DateTimeField(_('expire date'))
|
||||
objects = SessionManager()
|
||||
|
||||
class Meta:
|
||||
db_table = 'django_session'
|
||||
verbose_name = _('session')
|
||||
|
|
|
@ -1,35 +1,59 @@
|
|||
r"""
|
||||
>>> s = SessionWrapper(None)
|
||||
|
||||
Inject data into the session cache.
|
||||
>>> s._session_cache = {}
|
||||
>>> s._session_cache['some key'] = 'exists'
|
||||
>>> from django.contrib.sessions.backends.db import SessionStore as DatabaseSession
|
||||
>>> from django.contrib.sessions.backends.cache import SessionStore as CacheSession
|
||||
>>> from django.contrib.sessions.backends.file import SessionStore as FileSession
|
||||
|
||||
>>> s.accessed
|
||||
>>> db_session = DatabaseSession()
|
||||
>>> db_session.modified
|
||||
False
|
||||
>>> s.modified
|
||||
False
|
||||
|
||||
>>> s.pop('non existant key', 'does not exist')
|
||||
>>> db_session['cat'] = "dog"
|
||||
>>> db_session.modified
|
||||
True
|
||||
>>> db_session.pop('cat')
|
||||
'dog'
|
||||
>>> db_session.pop('some key', 'does not exist')
|
||||
'does not exist'
|
||||
>>> s.accessed
|
||||
>>> db_session.save()
|
||||
>>> db_session.exists(db_session.session_key)
|
||||
True
|
||||
>>> s.modified
|
||||
>>> db_session.delete(db_session.session_key)
|
||||
>>> db_session.exists(db_session.session_key)
|
||||
False
|
||||
|
||||
>>> s.pop('some key')
|
||||
'exists'
|
||||
>>> s.accessed
|
||||
>>> file_session = FileSession()
|
||||
>>> file_session.modified
|
||||
False
|
||||
>>> file_session['cat'] = "dog"
|
||||
>>> file_session.modified
|
||||
True
|
||||
>>> s.modified
|
||||
True
|
||||
|
||||
>>> s.pop('some key', 'does not exist')
|
||||
>>> file_session.pop('cat')
|
||||
'dog'
|
||||
>>> file_session.pop('some key', 'does not exist')
|
||||
'does not exist'
|
||||
>>> file_session.save()
|
||||
>>> file_session.exists(file_session.session_key)
|
||||
True
|
||||
>>> file_session.delete(file_session.session_key)
|
||||
>>> file_session.exists(file_session.session_key)
|
||||
False
|
||||
|
||||
>>> cache_session = CacheSession()
|
||||
>>> cache_session.modified
|
||||
False
|
||||
>>> cache_session['cat'] = "dog"
|
||||
>>> cache_session.modified
|
||||
True
|
||||
>>> cache_session.pop('cat')
|
||||
'dog'
|
||||
>>> cache_session.pop('some key', 'does not exist')
|
||||
'does not exist'
|
||||
>>> cache_session.save()
|
||||
>>> cache_session.delete(cache_session.session_key)
|
||||
>>> cache_session.exists(cache_session.session_key)
|
||||
False
|
||||
"""
|
||||
|
||||
from django.contrib.sessions.middleware import SessionWrapper
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
|
|
@ -4,8 +4,6 @@ from cStringIO import StringIO
|
|||
from urlparse import urlparse
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import authenticate, login
|
||||
from django.contrib.sessions.models import Session
|
||||
from django.contrib.sessions.middleware import SessionWrapper
|
||||
from django.core.handlers.base import BaseHandler
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.core.signals import got_request_exception
|
||||
|
@ -132,9 +130,10 @@ class Client:
|
|||
def _session(self):
|
||||
"Obtain the current session variables"
|
||||
if 'django.contrib.sessions' in settings.INSTALLED_APPS:
|
||||
engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
|
||||
cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None)
|
||||
if cookie:
|
||||
return SessionWrapper(cookie.value)
|
||||
return engine.SessionClass(cookie.value)
|
||||
return {}
|
||||
session = property(_session)
|
||||
|
||||
|
@ -247,24 +246,23 @@ class Client:
|
|||
"""
|
||||
user = authenticate(**credentials)
|
||||
if user and user.is_active and 'django.contrib.sessions' in settings.INSTALLED_APPS:
|
||||
obj = Session.objects.get_new_session_object()
|
||||
engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
|
||||
|
||||
# Create a fake request to store login details
|
||||
request = HttpRequest()
|
||||
request.session = SessionWrapper(obj.session_key)
|
||||
request.session = engine.SessionClass()
|
||||
login(request, user)
|
||||
|
||||
# Set the cookie to represent the session
|
||||
self.cookies[settings.SESSION_COOKIE_NAME] = obj.session_key
|
||||
self.cookies[settings.SESSION_COOKIE_NAME] = request.session.session_key
|
||||
self.cookies[settings.SESSION_COOKIE_NAME]['max-age'] = None
|
||||
self.cookies[settings.SESSION_COOKIE_NAME]['path'] = '/'
|
||||
self.cookies[settings.SESSION_COOKIE_NAME]['domain'] = settings.SESSION_COOKIE_DOMAIN
|
||||
self.cookies[settings.SESSION_COOKIE_NAME]['secure'] = settings.SESSION_COOKIE_SECURE or None
|
||||
self.cookies[settings.SESSION_COOKIE_NAME]['expires'] = None
|
||||
|
||||
# Set the session values
|
||||
Session.objects.save(obj.session_key, request.session._session,
|
||||
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
|
||||
# Save the session values
|
||||
request.session.save()
|
||||
|
||||
return True
|
||||
else:
|
||||
|
|
|
@ -10,18 +10,21 @@ Cookies contain a session ID -- not the data itself.
|
|||
Enabling sessions
|
||||
=================
|
||||
|
||||
Sessions are implemented via a piece of middleware_ and a Django model.
|
||||
Sessions are implemented via a piece of middleware_.
|
||||
|
||||
To enable session functionality, do these two things:
|
||||
To enable session functionality, do the following:
|
||||
|
||||
* Edit the ``MIDDLEWARE_CLASSES`` setting and make sure
|
||||
``MIDDLEWARE_CLASSES`` contains ``'django.contrib.sessions.middleware.SessionMiddleware'``.
|
||||
The default ``settings.py`` created by ``django-admin.py startproject`` has
|
||||
``SessionMiddleware`` activated.
|
||||
|
||||
* Add ``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting, and
|
||||
run ``manage.py syncdb`` to install the single database table that stores
|
||||
session data.
|
||||
* Add ``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting,
|
||||
and run ``manage.py syncdb`` to install the single database table
|
||||
that stores session data.
|
||||
|
||||
**New in development version**: this step is optional if you're not using
|
||||
the database session backend; see `configuring the session engine`_.
|
||||
|
||||
If you don't want to use sessions, you might as well remove the
|
||||
``SessionMiddleware`` line from ``MIDDLEWARE_CLASSES`` and ``'django.contrib.sessions'``
|
||||
|
@ -29,6 +32,44 @@ from your ``INSTALLED_APPS``. It'll save you a small bit of overhead.
|
|||
|
||||
.. _middleware: ../middleware/
|
||||
|
||||
Configuring the session engine
|
||||
==============================
|
||||
|
||||
**New in development version**.
|
||||
|
||||
By default, Django stores sessions in your database (using the model
|
||||
``django.contrib.sessions.models.Session``). Though this is convenient, in
|
||||
some setups it's faster to store session data elsewhere, so Django can be
|
||||
configured to store session data on your filesystem or in your cache.
|
||||
|
||||
Using file-based sessions
|
||||
-------------------------
|
||||
|
||||
To use file-based sessions, set the ``SESSION_ENGINE`` setting to
|
||||
``"django.contrib.sessions.backends.file"``.
|
||||
|
||||
You might also want to set the ``SESSION_FILE_PATH`` setting (which
|
||||
defaults to ``/tmp``) to control where Django stores session files. Be
|
||||
sure to check that your web server has permissions to read and write to
|
||||
this location.
|
||||
|
||||
Using cache-based sessions
|
||||
--------------------------
|
||||
|
||||
To store session data using Django's cache system, set ``SESSION_ENGINE``
|
||||
to ``"django.contrib.sessions.backends.cache"``. You'll want to make sure
|
||||
you've configured your cache; see the `cache documentation`_ for details.
|
||||
|
||||
.. _cache documentation: ../cache/
|
||||
|
||||
.. note::
|
||||
|
||||
You probably don't want to use cache-based sessions if you're not using
|
||||
the memcached cache backend. The local memory and simple cache backends
|
||||
don't retain data long enough to be good choices, and it'll be faster
|
||||
to use file or database sessions directly instead of sending everything
|
||||
through the file or database cache backends.
|
||||
|
||||
Using sessions in views
|
||||
=======================
|
||||
|
||||
|
@ -153,7 +194,18 @@ Here's a typical usage example::
|
|||
Using sessions out of views
|
||||
===========================
|
||||
|
||||
Internally, each session is just a normal Django model. The ``Session`` model
|
||||
The ``SessionStore`` which implements the session storage method can be imported
|
||||
and a API is available to manipulate the session data outside of a view::
|
||||
|
||||
>>> from django.contrib.sessions.engines.db import SessionStore
|
||||
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
|
||||
>>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10)
|
||||
>>> s['last_login']
|
||||
datetime.datetime(2005, 8, 20, 13, 35, 0)
|
||||
>>> s.save()
|
||||
|
||||
Or if you are using the ``django.contrib.sessions.engine.db`` each
|
||||
session is just a normal Django model. The ``Session`` model
|
||||
is defined in ``django/contrib/sessions/models.py``. Because it's a normal
|
||||
model, you can access sessions using the normal Django database API::
|
||||
|
||||
|
@ -245,6 +297,31 @@ Settings
|
|||
|
||||
A few `Django settings`_ give you control over session behavior:
|
||||
|
||||
SESSION_ENGINE
|
||||
--------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Default: ``django.contrib.sessions.backends.db``
|
||||
|
||||
Controls where Django stores session data. Valid values are:
|
||||
|
||||
* ``'django.contrib.sessions.backends.db'``
|
||||
* ``'django.contrib.sessions.backends.file'``
|
||||
* ``'django.contrib.sessions.backends.cache'``
|
||||
|
||||
See `configuring the session engine`_ for more details.
|
||||
|
||||
SESSION_FILE_PATH
|
||||
-----------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Default: ``/tmp/``
|
||||
|
||||
If you're using file-based session storage, this sets the directory in
|
||||
which Django will store session data.
|
||||
|
||||
SESSION_COOKIE_AGE
|
||||
------------------
|
||||
|
||||
|
|
|
@ -733,6 +733,21 @@ Default: ``'root@localhost'``
|
|||
The e-mail address that error messages come from, such as those sent to
|
||||
``ADMINS`` and ``MANAGERS``.
|
||||
|
||||
SESSION_ENGINE
|
||||
--------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Default: ``django.contrib.sessions.backends.db``
|
||||
|
||||
Controls where Django stores session data. Valid values are:
|
||||
|
||||
* ``'django.contrib.sessions.backends.db'``
|
||||
* ``'django.contrib.sessions.backends.file'``
|
||||
* ``'django.contrib.sessions.backends.cache'``
|
||||
|
||||
See the `session docs`_ for more details.
|
||||
|
||||
SESSION_COOKIE_AGE
|
||||
------------------
|
||||
|
||||
|
@ -775,6 +790,17 @@ Default: ``False``
|
|||
Whether to expire the session when the user closes his or her browser.
|
||||
See the `session docs`_.
|
||||
|
||||
SESSION_FILE_PATH
|
||||
-----------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Default: ``/tmp/``
|
||||
|
||||
If you're using file-based session storage, this sets the directory in
|
||||
which Django will store session data. See the `session docs`_ for
|
||||
more details.
|
||||
|
||||
SESSION_SAVE_EVERY_REQUEST
|
||||
--------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue