Browse Source

Fixed #33562 -- Made HttpResponse.set_cookie() support timedelta for the max_age argument.

Luke Plant 3 years ago
parent
commit
ae2da5ba65

+ 6 - 0
django/http/response.py

@@ -227,6 +227,10 @@ class HttpResponseBase:
         - a naive ``datetime.datetime`` object in UTC,
         - an aware ``datetime.datetime`` object in any time zone.
         If it is a ``datetime.datetime`` object then calculate ``max_age``.
+
+        ``max_age`` can be:
+        - int/float specifying seconds,
+        - ``datetime.timedelta`` object.
         """
         self.cookies[key] = value
         if expires is not None:
@@ -246,6 +250,8 @@ class HttpResponseBase:
         else:
             self.cookies[key]["expires"] = ""
         if max_age is not None:
+            if isinstance(max_age, datetime.timedelta):
+                max_age = max_age.total_seconds()
             self.cookies[key]["max-age"] = int(max_age)
             # IE requires expires, so set it if hasn't been already.
             if not expires:

+ 9 - 3
docs/ref/request-response.txt

@@ -853,9 +853,15 @@ Methods
     Sets a cookie. The parameters are the same as in the
     :class:`~http.cookies.Morsel` cookie object in the Python standard library.
 
-    * ``max_age`` should be an integer number of seconds, or ``None`` (default)
-      if the cookie should last only as long as the client's browser session.
-      If ``expires`` is not specified, it will be calculated.
+    * ``max_age`` should be a :class:`~datetime.timedelta` object, an integer
+      number of seconds, or ``None`` (default) if the cookie should last only
+      as long as the client's browser session. If ``expires`` is not specified,
+      it will be calculated.
+
+      .. versionchanged:: 4.1
+
+        Support for ``timedelta`` objects was added.
+
     * ``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``

+ 2 - 1
docs/releases/4.1.txt

@@ -281,7 +281,8 @@ Models
 Requests and Responses
 ~~~~~~~~~~~~~~~~~~~~~~
 
-* ...
+* :meth:`.HttpResponse.set_cookie` now supports :class:`~datetime.timedelta`
+  objects for the ``max_age`` argument.
 
 Security
 ~~~~~~~~

+ 5 - 0
tests/responses/test_cookie.py

@@ -71,6 +71,11 @@ class SetCookieTests(SimpleTestCase):
         response.set_cookie("max_age", max_age=10.6)
         self.assertEqual(response.cookies["max_age"]["max-age"], 10)
 
+    def test_max_age_timedelta(self):
+        response = HttpResponse()
+        response.set_cookie("max_age", max_age=timedelta(hours=1))
+        self.assertEqual(response.cookies["max_age"]["max-age"], 3600)
+
     def test_httponly_cookie(self):
         response = HttpResponse()
         response.set_cookie("example", httponly=True)

+ 7 - 0
tests/signed_cookies_tests/tests.py

@@ -62,6 +62,13 @@ class SignedCookieTest(SimpleTestCase):
             with self.assertRaises(signing.SignatureExpired):
                 request.get_signed_cookie("c", max_age=timedelta(seconds=10))
 
+    def test_set_signed_cookie_max_age_argument(self):
+        response = HttpResponse()
+        response.set_signed_cookie("c", "value", max_age=100)
+        self.assertEqual(response.cookies["c"]["max-age"], 100)
+        response.set_signed_cookie("d", "value", max_age=timedelta(hours=2))
+        self.assertEqual(response.cookies["d"]["max-age"], 7200)
+
     @override_settings(SECRET_KEY=b"\xe7")
     def test_signed_cookies_with_binary_key(self):
         response = HttpResponse()