6
6
import socket
7
7
from functools import lru_cache
8
8
9
+ from asgiref .sync import iscoroutinefunction , markcoroutinefunction
9
10
from django .conf import settings
10
11
from django .utils .module_loading import import_string
11
12
@@ -62,14 +63,50 @@ class DebugToolbarMiddleware:
62
63
on outgoing response.
63
64
"""
64
65
66
+ sync_capable = True
67
+ async_capable = True
68
+
65
69
def __init__ (self , get_response ):
66
70
self .get_response = get_response
71
+ # If get_response is a coroutine function, turns us into async mode so
72
+ # a thread is not consumed during a whole request.
73
+ self .async_mode = iscoroutinefunction (self .get_response )
74
+
75
+ if self .async_mode :
76
+ # Mark the class as async-capable, but do the actual switch inside
77
+ # __call__ to avoid swapping out dunder methods.
78
+ markcoroutinefunction (self )
67
79
68
80
def __call__ (self , request ):
69
81
# Decide whether the toolbar is active for this request.
82
+ if self .async_mode :
83
+ return self .__acall__ (request )
84
+ # Decide whether the toolbar is active for this request.
70
85
show_toolbar = get_show_toolbar ()
71
86
if not show_toolbar (request ) or DebugToolbar .is_toolbar_request (request ):
72
87
return self .get_response (request )
88
+ toolbar = DebugToolbar (request , self .get_response )
89
+ # Activate instrumentation ie. monkey-patch.
90
+ for panel in toolbar .enabled_panels :
91
+ panel .enable_instrumentation ()
92
+ try :
93
+ # Run panels like Django middleware.
94
+ response = toolbar .process_request (request )
95
+ finally :
96
+ clear_stack_trace_caches ()
97
+ # Deactivate instrumentation ie. monkey-unpatch. This must run
98
+ # regardless of the response. Keep 'return' clauses below.
99
+ for panel in reversed (toolbar .enabled_panels ):
100
+ panel .disable_instrumentation ()
101
+
102
+ return self ._postprocess (request , response , toolbar )
103
+
104
+ async def __acall__ (self , request ):
105
+ # Decide whether the toolbar is active for this request.
106
+ show_toolbar = get_show_toolbar ()
107
+ if not show_toolbar (request ) or DebugToolbar .is_toolbar_request (request ):
108
+ response = await self .get_response (request )
109
+ return response
73
110
74
111
toolbar = DebugToolbar (request , self .get_response )
75
112
@@ -78,14 +115,20 @@ def __call__(self, request):
78
115
panel .enable_instrumentation ()
79
116
try :
80
117
# Run panels like Django middleware.
81
- response = toolbar .process_request (request )
118
+ response = await toolbar .process_request (request )
82
119
finally :
83
120
clear_stack_trace_caches ()
84
121
# Deactivate instrumentation ie. monkey-unpatch. This must run
85
122
# regardless of the response. Keep 'return' clauses below.
86
123
for panel in reversed (toolbar .enabled_panels ):
87
124
panel .disable_instrumentation ()
88
125
126
+ return self ._postprocess (request , response , toolbar )
127
+
128
+ def _postprocess (self , request , response , toolbar ):
129
+ """
130
+ Post-process the response.
131
+ """
89
132
# Generate the stats for all requests when the toolbar is being shown,
90
133
# but not necessarily inserted.
91
134
for panel in reversed (toolbar .enabled_panels ):
0 commit comments