summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Galler <michael.galler@schnapptack.de>2020-08-20 18:41:22 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-08-26 07:13:49 +0200
commit547a07fa7ec4364ea9ecd2aabfdd16ee4c63003c (patch)
treec34620659c055b19d3948d7a13e5303c8f73af09
parent0b0658111cba538b91072b9a133fd5545f3f46d1 (diff)
Fixed #31905 -- Made MiddlewareMixin call process_request()/process_response() with thread sensitive.
Co-authored-by: Carlton Gibson <carlton.gibson@noumenal.es>
-rw-r--r--django/utils/deprecation.py10
-rw-r--r--docs/releases/3.1.1.txt4
-rw-r--r--tests/deprecation/test_middleware_mixin.py43
3 files changed, 54 insertions, 3 deletions
diff --git a/django/utils/deprecation.py b/django/utils/deprecation.py
index 3582fcf3a3..b2c681b33c 100644
--- a/django/utils/deprecation.py
+++ b/django/utils/deprecation.py
@@ -126,10 +126,16 @@ class MiddlewareMixin:
"""
response = None
if hasattr(self, 'process_request'):
- response = await sync_to_async(self.process_request)(request)
+ response = await sync_to_async(
+ self.process_request,
+ thread_sensitive=True,
+ )(request)
response = response or await self.get_response(request)
if hasattr(self, 'process_response'):
- response = await sync_to_async(self.process_response)(request, response)
+ response = await sync_to_async(
+ self.process_response,
+ thread_sensitive=True,
+ )(request, response)
return response
def _get_response_none_deprecation(self, get_response):
diff --git a/docs/releases/3.1.1.txt b/docs/releases/3.1.1.txt
index fd0843c2ae..6359f181fa 100644
--- a/docs/releases/3.1.1.txt
+++ b/docs/releases/3.1.1.txt
@@ -35,3 +35,7 @@ Bugfixes
* Reverted a deprecation in Django 3.1 that caused a crash when passing
deprecated keyword arguments to a queryset in
``TemplateView.get_context_data()`` (:ticket:`31877`).
+
+* Enforced thread sensitivity of the :class:`MiddlewareMixin.process_request()
+ <django.utils.deprecation.MiddlewareMixin>` and ``process_response()`` hooks
+ when in an async context (:ticket:`31905`).
diff --git a/tests/deprecation/test_middleware_mixin.py b/tests/deprecation/test_middleware_mixin.py
index f03d9168ec..c90aeb8360 100644
--- a/tests/deprecation/test_middleware_mixin.py
+++ b/tests/deprecation/test_middleware_mixin.py
@@ -1,11 +1,18 @@
+import threading
+
+from asgiref.sync import async_to_sync
+
from django.contrib.sessions.middleware import SessionMiddleware
+from django.db import connection
+from django.http.request import HttpRequest
+from django.http.response import HttpResponse
from django.middleware.cache import (
CacheMiddleware, FetchFromCacheMiddleware, UpdateCacheMiddleware,
)
from django.middleware.common import CommonMiddleware
from django.middleware.security import SecurityMiddleware
from django.test import SimpleTestCase
-from django.utils.deprecation import RemovedInDjango40Warning
+from django.utils.deprecation import MiddlewareMixin, RemovedInDjango40Warning
class MiddlewareMixinTests(SimpleTestCase):
@@ -37,3 +44,37 @@ class MiddlewareMixinTests(SimpleTestCase):
with self.subTest(middleware=middleware):
with self.assertRaisesMessage(RemovedInDjango40Warning, self.msg):
middleware()
+
+ def test_sync_to_async_uses_base_thread_and_connection(self):
+ """
+ The process_request() and process_response() hooks must be called with
+ the sync_to_async thread_sensitive flag enabled, so that database
+ operations use the correct thread and connection.
+ """
+ def request_lifecycle():
+ """Fake request_started/request_finished."""
+ return (threading.get_ident(), id(connection))
+
+ async def get_response(self):
+ return HttpResponse()
+
+ class SimpleMiddleWare(MiddlewareMixin):
+ def process_request(self, request):
+ request.thread_and_connection = request_lifecycle()
+
+ def process_response(self, request, response):
+ response.thread_and_connection = request_lifecycle()
+ return response
+
+ threads_and_connections = []
+ threads_and_connections.append(request_lifecycle())
+
+ request = HttpRequest()
+ response = async_to_sync(SimpleMiddleWare(get_response))(request)
+ threads_and_connections.append(request.thread_and_connection)
+ threads_and_connections.append(response.thread_and_connection)
+
+ threads_and_connections.append(request_lifecycle())
+
+ self.assertEqual(len(threads_and_connections), 4)
+ self.assertEqual(len(set(threads_and_connections)), 1)