Allow setting HttpResponse cookie expiry times with datetime objects.

Patch from SmileyChris. Fixed #7770.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@13809 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2010-09-12 20:52:49 +00:00
parent 7c075440ea
commit 2d4da641a6
3 changed files with 55 additions and 5 deletions

View File

@ -1,5 +1,7 @@
import datetime
import os import os
import re import re
import time
from Cookie import BaseCookie, SimpleCookie, CookieError from Cookie import BaseCookie, SimpleCookie, CookieError
from pprint import pformat from pprint import pformat
from urllib import urlencode from urllib import urlencode
@ -12,6 +14,7 @@ except ImportError:
from django.utils.datastructures import MultiValueDict, ImmutableList from django.utils.datastructures import MultiValueDict, ImmutableList
from django.utils.encoding import smart_str, iri_to_uri, force_unicode from django.utils.encoding import smart_str, iri_to_uri, force_unicode
from django.utils.http import cookie_date
from django.http.multipartparser import MultiPartParser from django.http.multipartparser import MultiPartParser
from django.conf import settings from django.conf import settings
from django.core.files import uploadhandler from django.core.files import uploadhandler
@ -373,11 +376,32 @@ class HttpResponse(object):
def set_cookie(self, key, value='', max_age=None, expires=None, path='/', def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
domain=None, secure=False): domain=None, secure=False):
"""
Sets a cookie.
``expires`` can be a string in the correct format or a
``datetime.datetime`` object in UTC. If ``expires`` is a datetime
object then ``max_age`` will be calculated.
"""
self.cookies[key] = value self.cookies[key] = value
if expires is not None:
if isinstance(expires, datetime.datetime):
delta = expires - expires.utcnow()
# Add one second so the date matches exactly (a fraction of
# time gets lost between converting to a timedelta and
# then the date string).
delta = delta + datetime.timedelta(seconds=1)
# Just set max_age - the max_age logic will set expires.
expires = None
max_age = max(0, delta.days * 86400 + delta.seconds)
else:
self.cookies[key]['expires'] = expires
if max_age is not None: if max_age is not None:
self.cookies[key]['max-age'] = max_age self.cookies[key]['max-age'] = max_age
if expires is not None: # IE requires expires, so set it if hasn't been already.
self.cookies[key]['expires'] = expires if not expires:
self.cookies[key]['expires'] = cookie_date(time.time() +
max_age)
if path is not None: if path is not None:
self.cookies[key]['path'] = path self.cookies[key]['path'] = path
if domain is not None: if domain is not None:

View File

@ -529,8 +529,11 @@ Methods
* ``max_age`` should be a number of seconds, or ``None`` (default) if * ``max_age`` should be a number of seconds, or ``None`` (default) if
the cookie should last only as long as the client's browser session. the cookie should last only as long as the client's browser session.
* ``expires`` should be a string in the format If ``expires`` is not specified, it will be calculated.
``"Wdy, DD-Mon-YY HH:MM:SS GMT"``. * ``expires`` should either be a string in the format
``"Wdy, DD-Mon-YY HH:MM:SS GMT"`` or a ``datetime.datetime`` object
in UTC. If ``expires`` is a ``datetime`` object, the ``max_age``
will be calculated.
* Use ``domain`` if you want to set a cross-domain cookie. For example, * Use ``domain`` if you want to set a cross-domain cookie. For example,
``domain=".lawrence.com"`` will set a cookie that is readable by ``domain=".lawrence.com"`` will set a cookie that is readable by
the domains www.lawrence.com, blogs.lawrence.com and the domains www.lawrence.com, blogs.lawrence.com and

View File

@ -1,5 +1,5 @@
""" """
>>> from django.http import HttpRequest >>> from django.http import HttpRequest, HttpResponse
>>> print repr(HttpRequest()) >>> print repr(HttpRequest())
<HttpRequest <HttpRequest
GET:{}, GET:{},
@ -44,4 +44,27 @@ https://www.example.com/asdf
>>> request.path = '' >>> request.path = ''
>>> print request.build_absolute_uri(location="/path/with:colons") >>> print request.build_absolute_uri(location="/path/with:colons")
http://www.example.com/path/with:colons http://www.example.com/path/with:colons
# Test cookie datetime expiration logic
>>> from datetime import datetime, timedelta
>>> delta = timedelta(seconds=10)
>>> response = HttpResponse()
>>> response.set_cookie('datetime', expires=datetime.utcnow()+delta)
>>> datetime_cookie = response.cookies['datetime']
>>> datetime_cookie['max-age']
10
>>> response.set_cookie('datetime', expires=datetime(2028, 1, 1, 4, 5, 6))
>>> response.cookies['datetime']['expires']
'Sat, 01-Jan-2028 04:05:06 GMT'
# Test automatically setting cookie expires if only max_age is provided
>>> response.set_cookie('max_age', max_age=10)
>>> max_age_cookie = response.cookies['max_age']
>>> max_age_cookie['max-age']
10
>>> from django.utils.http import cookie_date
>>> import time
>>> max_age_cookie['expires'] == cookie_date(time.time()+10)
True
""" """