mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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:
		
							
								
								
									
										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): | ||||
|   | ||||
| @@ -15,7 +15,7 @@ class SessionStore(SessionBase): | ||||
|         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): | ||||
|   | ||||
| @@ -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 | ||||
| ========================== | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user