Fixed #2548: added get/set_expiry methods to session objects. Thanks, Amit Upadhyay and SmileyChris.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@7586 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jacob Kaplan-Moss 2008-06-07 20:28:06 +00:00
parent 50de13343b
commit 8d4f79a799
8 changed files with 221 additions and 12 deletions

View File

@ -360,7 +360,7 @@ answer newbie questions, and generally made Django that much better:
Makoto Tsuyuki <mtsuyuki@gmail.com>
tt@gurgle.no
David Tulig <david.tulig@gmail.com>
Amit Upadhyay
Amit Upadhyay <http://www.amitu.com/blog/>
Geert Vanderkelen
I.S. van Oostveen <v.oostveen@idca.nl>
viestards.lists@gmail.com

View File

@ -289,7 +289,7 @@ SESSION_COOKIE_DOMAIN = None # A string like ".lawren
SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
SESSION_COOKIE_PATH = '/' # The path of the session cookie.
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_EXPIRE_AT_BROWSER_CLOSE = False # Whether a user's session cookie expires when they close their browser.
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # The module to store session data
SESSION_FILE_PATH = None # Directory to store session files if using the file session module. If None, the backend will use a sensible default.

View File

@ -4,6 +4,7 @@ import os
import random
import sys
import time
from datetime import datetime, timedelta
from django.conf import settings
from django.core.exceptions import SuspiciousOperation
@ -128,6 +129,62 @@ class SessionBase(object):
_session = property(_get_session)
def get_expiry_age(self):
"""Get the number of seconds until the session expires."""
expiry = self.get('_session_expiry')
if not expiry: # Checks both None and 0 cases
return settings.SESSION_COOKIE_AGE
if not isinstance(expiry, datetime):
return expiry
delta = expiry - datetime.now()
return delta.days * 86400 + delta.seconds
def get_expiry_date(self):
"""Get session the expiry date (as a datetime object)."""
expiry = self.get('_session_expiry')
if isinstance(expiry, datetime):
return expiry
if not expiry: # Checks both None and 0 cases
expiry = settings.SESSION_COOKIE_AGE
return datetime.now() + timedelta(seconds=expiry)
def set_expiry(self, value):
"""
Sets a custom expiration for the session. ``value`` can be an integer, a
Python ``datetime`` or ``timedelta`` object or ``None``.
If ``value`` is an integer, the session will expire after that many
seconds of inactivity. If set to ``0`` then the session will expire on
browser close.
If ``value`` is a ``datetime`` or ``timedelta`` object, the session
will expire at that specific future time.
If ``value`` is ``None``, the session uses the global session expiry
policy.
"""
if value is None:
# Remove any custom expiration for this session.
try:
del self['_session_expiry']
except KeyError:
pass
return
if isinstance(value, timedelta):
value = datetime.now() + value
self['_session_expiry'] = value
def get_expire_at_browser_close(self):
"""
Returns ``True`` if the session is set to expire when the browser
closes, and ``False`` if there's an expiry date. Use
``get_expiry_date()`` or ``get_expiry_age()`` to find the actual expiry
date/age, if there is one.
"""
if self.get('_session_expiry') is None:
return settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
return self.get('_session_expiry') == 0
# Methods that child classes must implement.
def exists(self, session_key):

View File

@ -4,23 +4,23 @@ from django.core.cache import cache
class SessionStore(SessionBase):
"""
A cache-based session store.
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)
self._cache.set(self.session_key, self._session, self.get_expiry_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)

View File

@ -41,7 +41,7 @@ class SessionStore(SessionBase):
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)
expire_date = self.get_expiry_date()
)
def delete(self, session_key):

View File

@ -26,14 +26,14 @@ class SessionMiddleware(object):
if accessed:
patch_vary_headers(response, ('Cookie',))
if modified or settings.SESSION_SAVE_EVERY_REQUEST:
if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
if request.session.get_expire_at_browser_close():
max_age = None
expires = None
else:
max_age = settings.SESSION_COOKIE_AGE
expires_time = time.time() + settings.SESSION_COOKIE_AGE
max_age = request.session.get_expiry_age()
expires_time = time.time() + max_age
expires = cookie_date(expires_time)
# Save the seesion data and refresh the client cookie.
# Save the session data and refresh the client cookie.
request.session.save()
response.set_cookie(settings.SESSION_COOKIE_NAME,
request.session.session_key, max_age=max_age,

View File

@ -88,6 +88,100 @@ False
>>> s.pop('some key', 'does not exist')
'does not exist'
#########################
# Custom session expiry #
#########################
>>> from django.conf import settings
>>> from datetime import datetime, timedelta
>>> td10 = timedelta(seconds=10)
# A normal session has a max age equal to settings
>>> s.get_expiry_age() == settings.SESSION_COOKIE_AGE
True
# So does a custom session with an idle expiration time of 0 (but it'll expire
# at browser close)
>>> s.set_expiry(0)
>>> s.get_expiry_age() == settings.SESSION_COOKIE_AGE
True
# Custom session idle expiration time
>>> s.set_expiry(10)
>>> delta = s.get_expiry_date() - datetime.now()
>>> delta.seconds in (9, 10)
True
>>> age = s.get_expiry_age()
>>> age in (9, 10)
True
# Custom session fixed expiry date (timedelta)
>>> s.set_expiry(td10)
>>> delta = s.get_expiry_date() - datetime.now()
>>> delta.seconds in (9, 10)
True
>>> age = s.get_expiry_age()
>>> age in (9, 10)
True
# Custom session fixed expiry date (fixed datetime)
>>> s.set_expiry(datetime.now() + td10)
>>> delta = s.get_expiry_date() - datetime.now()
>>> delta.seconds in (9, 10)
True
>>> age = s.get_expiry_age()
>>> age in (9, 10)
True
# Set back to default session age
>>> s.set_expiry(None)
>>> s.get_expiry_age() == settings.SESSION_COOKIE_AGE
True
# Allow to set back to default session age even if no alternate has been set
>>> s.set_expiry(None)
# We're changing the setting then reverting back to the original setting at the
# end of these tests.
>>> original_expire_at_browser_close = settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = False
# Custom session age
>>> s.set_expiry(10)
>>> s.get_expire_at_browser_close()
False
# Custom expire-at-browser-close
>>> s.set_expiry(0)
>>> s.get_expire_at_browser_close()
True
# Default session age
>>> s.set_expiry(None)
>>> s.get_expire_at_browser_close()
False
>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = True
# Custom session age
>>> s.set_expiry(10)
>>> s.get_expire_at_browser_close()
False
# Custom expire-at-browser-close
>>> s.set_expiry(0)
>>> s.get_expire_at_browser_close()
True
# Default session age
>>> s.set_expiry(None)
>>> s.get_expire_at_browser_close()
True
>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = original_expire_at_browser_close
"""
if __name__ == '__main__':

View File

@ -80,19 +80,24 @@ attribute, which is a dictionary-like object. You can read it and write to it.
It implements the following standard dictionary methods:
* ``__getitem__(key)``
Example: ``fav_color = request.session['fav_color']``
* ``__setitem__(key, value)``
Example: ``request.session['fav_color'] = 'blue'``
* ``__delitem__(key)``
Example: ``del request.session['fav_color']``. This raises ``KeyError``
if the given ``key`` isn't already in the session.
* ``__contains__(key)``
Example: ``'fav_color' in request.session``
* ``get(key, default=None)``
Example: ``fav_color = request.session.get('fav_color', 'red')``
* ``keys()``
@ -101,23 +106,70 @@ It implements the following standard dictionary methods:
* ``setdefault()`` (**New in Django development version**)
It also has these three methods:
It also has these methods:
* ``set_test_cookie()``
Sets a test cookie to determine whether the user's browser supports
cookies. Due to the way cookies work, you won't be able to test this
until the user's next page request. See "Setting test cookies" below for
more information.
* ``test_cookie_worked()``
Returns either ``True`` or ``False``, depending on whether the user's
browser accepted the test cookie. Due to the way cookies work, you'll
have to call ``set_test_cookie()`` on a previous, separate page request.
See "Setting test cookies" below for more information.
* ``delete_test_cookie()``
Deletes the test cookie. Use this to clean up after yourself.
* ``set_expiry(value)``
**New in Django development version**
Sets the expiration time for the session. You can pass a number of
different values:
* If ``value`` is an integer, the session will expire after that
many seconds of inactivity. For example, calling
``request.session.set_expiry(300)`` would make the session expire
in 5 minutes.
* If ``value`` is a ``datetime`` or ``timedelta`` object, the
session will expire at that specific time.
* If ``value`` is ``0`` then the user's session cookie will expire
when their browser is closed.
* If ``value`` is ``None``, the session reverts to using the global
session expiry policy.
* ``get_expiry_age()``
**New in Django development version**
Returns the number of seconds until this session expires. For sessions
with no custom expiration (or those set to expire at browser close), this
will equal ``settings.SESSION_COOKIE_AGE``.
* ``get_expiry_date()``
**New in Django development version**
Returns the date this session will expire. For sessions with no custom
expiration (or those set to expire at browser close), this will equal the
date ``settings.SESSION_COOKIE_AGE`` seconds from now.
* ``get_expire_at_browser_close()``
**New in Django development version**
Returns either ``True`` or ``False``, depending on whether the user's
session cookie will expire when their browser is closed.
You can edit ``request.session`` at any point in your view. You can edit it
multiple times.
@ -278,6 +330,12 @@ browser-length cookies -- cookies that expire as soon as the user closes his or
her browser. Use this if you want people to have to log in every time they open
a browser.
**New in Django development version**
This setting is a global default and can be overwritten at a per-session level
by explicitly calling ``request.session.set_expiry()`` as described above in
`using sessions in views`_.
Clearing the session table
==========================