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:
parent
50de13343b
commit
8d4f79a799
2
AUTHORS
2
AUTHORS
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
|
@ -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):
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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__':
|
||||
|
|
|
@ -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
|
||||
==========================
|
||||
|
||||
|
|
Loading…
Reference in New Issue