diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py
index 718cc54..ec29950 100644
a
|
b
|
class SessionBase(object):
|
301 | 301 | key = self.session_key |
302 | 302 | self.create() |
303 | 303 | self._session_cache = data |
304 | | self.delete(key) |
| 304 | if key: |
| 305 | self.delete(key) |
305 | 306 | |
306 | 307 | # Methods that child classes must implement. |
307 | 308 | |
diff --git a/django/contrib/sessions/backends/db.py b/django/contrib/sessions/backends/db.py
index ae2470e..63701c1 100644
a
|
b
|
class SessionStore(SessionBase):
|
83 | 83 | using = router.db_for_write(self.model, instance=obj) |
84 | 84 | try: |
85 | 85 | with transaction.atomic(using=using): |
86 | | obj.save(force_insert=must_create, using=using) |
| 86 | obj.save(force_insert=must_create, force_update=not must_create, using=using) |
87 | 87 | except IntegrityError: |
88 | 88 | if must_create: |
89 | 89 | raise CreateError |
diff --git a/tests/defer_regress/tests.py b/tests/defer_regress/tests.py
index cc1658c..8e224fd 100644
a
|
b
|
class DeferRegressionTest(TestCase):
|
131 | 131 | s = SessionStore(SESSION_KEY) |
132 | 132 | s.clear() |
133 | 133 | s["item"] = item |
134 | | s.save() |
| 134 | s.save(must_create=True) |
135 | 135 | |
136 | 136 | s = SessionStore(SESSION_KEY) |
137 | 137 | s.modified = True |
diff --git a/tests/sessions_tests/tests.py b/tests/sessions_tests/tests.py
index d2188f4..0488b38 100644
a
|
b
|
class DatabaseSessionTests(SessionTestsMixin, TestCase):
|
424 | 424 | # ... and one is deleted. |
425 | 425 | self.assertEqual(1, self.model.objects.count()) |
426 | 426 | |
| 427 | def test_ticket_21608(self): |
| 428 | # Test for #21608 - Logged out sessions are resurrected by concurrent requests. |
| 429 | |
| 430 | # Create new session. |
| 431 | SESSION_KEY = 'tkniiqcv0js5reo8y0ofrywrhmwnt9xw' |
| 432 | s1 = DatabaseSession(SESSION_KEY) |
| 433 | s1.save(must_create=True) |
| 434 | |
| 435 | # Logout in an other context. |
| 436 | s2 = DatabaseSession(SESSION_KEY) |
| 437 | s2.delete() |
| 438 | |
| 439 | # Modify session in first context. |
| 440 | s1.modified = True |
| 441 | try: |
| 442 | s1.save() # This should throw an exception as the session is deleted, not resurrect it. |
| 443 | except: |
| 444 | pass |
| 445 | |
| 446 | with self.assertRaises(Session.DoesNotExist): |
| 447 | Session.objects.get(pk=SESSION_KEY) |
| 448 | |
427 | 449 | |
428 | 450 | @override_settings(USE_TZ=True) |
429 | 451 | class DatabaseSessionWithTimeZoneTests(DatabaseSessionTests): |