Browse Source

Refs #29708 -- Made SessionBase store expiry as string.

Adam Johnson 3 years ago
parent
commit
436862787c

+ 7 - 1
django/contrib/sessions/backends/base.py

@@ -210,8 +210,10 @@ class SessionBase:
 
         if not expiry:   # Checks both None and 0 cases
             return self.get_session_cookie_age()
-        if not isinstance(expiry, datetime):
+        if not isinstance(expiry, (datetime, str)):
             return expiry
+        if isinstance(expiry, str):
+            expiry = datetime.fromisoformat(expiry)
         delta = expiry - modification
         return delta.days * 86400 + delta.seconds
 
@@ -233,6 +235,8 @@ class SessionBase:
 
         if isinstance(expiry, datetime):
             return expiry
+        elif isinstance(expiry, str):
+            return datetime.fromisoformat(expiry)
         expiry = expiry or self.get_session_cookie_age()
         return modification + timedelta(seconds=expiry)
 
@@ -260,6 +264,8 @@ class SessionBase:
             return
         if isinstance(value, timedelta):
             value = timezone.now() + value
+        if isinstance(value, datetime):
+            value = value.isoformat()
         self['_session_expiry'] = value
 
     def get_expire_at_browser_close(self):

+ 2 - 4
docs/topics/http/sessions.txt

@@ -258,10 +258,8 @@ You can edit it multiple times.
         ``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 date/time. Note that ``datetime``
-        and ``timedelta`` values are only serializable if you are using the
-        :class:`~django.contrib.sessions.serializers.PickleSerializer`.
+      * If ``value`` is a ``datetime`` or ``timedelta`` object, the session
+        will expire at that specific date/time.
 
       * If ``value`` is ``0``, the user's session cookie will expire
         when the user's web browser is closed.

+ 14 - 19
tests/sessions_tests/tests.py

@@ -333,25 +333,20 @@ class SessionTestsMixin:
         self.assertEqual(self.session.decode(encoded), {})
 
     def test_actual_expiry(self):
-        # this doesn't work with JSONSerializer (serializing timedelta)
-        with override_settings(SESSION_SERIALIZER='django.contrib.sessions.serializers.PickleSerializer'):
-            self.session = self.backend()  # reinitialize after overriding settings
-
-            # Regression test for #19200
-            old_session_key = None
-            new_session_key = None
-            try:
-                self.session['foo'] = 'bar'
-                self.session.set_expiry(-timedelta(seconds=10))
-                self.session.save()
-                old_session_key = self.session.session_key
-                # With an expiry date in the past, the session expires instantly.
-                new_session = self.backend(self.session.session_key)
-                new_session_key = new_session.session_key
-                self.assertNotIn('foo', new_session)
-            finally:
-                self.session.delete(old_session_key)
-                self.session.delete(new_session_key)
+        old_session_key = None
+        new_session_key = None
+        try:
+            self.session['foo'] = 'bar'
+            self.session.set_expiry(-timedelta(seconds=10))
+            self.session.save()
+            old_session_key = self.session.session_key
+            # With an expiry date in the past, the session expires instantly.
+            new_session = self.backend(self.session.session_key)
+            new_session_key = new_session.session_key
+            self.assertNotIn('foo', new_session)
+        finally:
+            self.session.delete(old_session_key)
+            self.session.delete(new_session_key)
 
     def test_session_load_does_not_create_record(self):
         """