Skip to content

Commit afb4e40

Browse files
committed
add utils to decorate a view with an async middleware
1 parent 11dfb0b commit afb4e40

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

django_async_extensions/utils/__init__.py

Whitespace-only changes.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
from functools import wraps
2+
3+
from asgiref.sync import async_to_sync, iscoroutinefunction, sync_to_async
4+
5+
6+
def decorator_from_middleware_with_args(middleware_class):
7+
"""
8+
Like decorator_from_middleware, but return a function
9+
that accepts the arguments to be passed to the middleware_class.
10+
Use like::
11+
12+
cache_page = decorator_from_middleware_with_args(CacheMiddleware)
13+
# ...
14+
15+
@cache_page(3600)
16+
def my_view(request):
17+
# ...
18+
"""
19+
return make_middleware_decorator(middleware_class)
20+
21+
22+
def decorator_from_middleware(middleware_class):
23+
"""
24+
Given a middleware class (not an instance), return a view decorator. This
25+
lets you use middleware functionality on a per-view basis. The middleware
26+
is created with no params passed.
27+
"""
28+
return make_middleware_decorator(middleware_class)()
29+
30+
31+
def make_middleware_decorator(middleware_class):
32+
def _make_decorator(*m_args, **m_kwargs):
33+
def _decorator(view_func):
34+
middleware = middleware_class(view_func, *m_args, **m_kwargs)
35+
36+
async def _pre_process_request(request, *args, **kwargs):
37+
if hasattr(middleware, "process_request"):
38+
result = await middleware.process_request(request)
39+
if result is not None:
40+
return result
41+
if hasattr(middleware, "process_view"):
42+
if iscoroutinefunction(middleware.process_view):
43+
result = await middleware.process_view(
44+
request, view_func, args, kwargs
45+
)
46+
else:
47+
result = await sync_to_async(middleware.process_view)(
48+
request, view_func, args, kwargs
49+
)
50+
if result is not None:
51+
return result
52+
return None
53+
54+
async def _process_exception(request, exception):
55+
if hasattr(middleware, "process_exception"):
56+
if iscoroutinefunction(middleware.process_exception):
57+
result = await middleware.process_exception(request, exception)
58+
else:
59+
result = await sync_to_async(middleware.process_exception)(
60+
request, exception
61+
)
62+
if result is not None:
63+
return result
64+
raise
65+
66+
async def _post_process_request(request, response):
67+
if hasattr(response, "render") and callable(response.render):
68+
if hasattr(middleware, "process_template_response"):
69+
if iscoroutinefunction(middleware.process_template_response):
70+
response = await middleware.process_template_response(
71+
request, response
72+
)
73+
else:
74+
response = await sync_to_async(
75+
middleware.process_template_response
76+
)(request, response)
77+
# Defer running of process_response until after the template
78+
# has been rendered:
79+
if hasattr(middleware, "process_response"):
80+
81+
async def callback(response):
82+
return await middleware.process_response(request, response)
83+
84+
response.add_post_render_callback(async_to_sync(callback))
85+
else:
86+
if hasattr(middleware, "process_response"):
87+
return await middleware.process_response(request, response)
88+
return response
89+
90+
if iscoroutinefunction(view_func):
91+
92+
async def _view_wrapper(request, *args, **kwargs):
93+
result = await _pre_process_request(request, *args, **kwargs)
94+
if result is not None:
95+
return result
96+
97+
try:
98+
response = await view_func(request, *args, **kwargs)
99+
except Exception as e:
100+
result = await _process_exception(request, e)
101+
if result is not None:
102+
return result
103+
104+
return await _post_process_request(request, response)
105+
106+
else:
107+
108+
def _view_wrapper(request, *args, **kwargs):
109+
result = async_to_sync(_pre_process_request)(
110+
request, *args, **kwargs
111+
)
112+
if result is not None:
113+
return result
114+
115+
try:
116+
response = view_func(request, *args, **kwargs)
117+
except Exception as e:
118+
result = async_to_sync(_process_exception)(request, e)
119+
if result is not None:
120+
return result
121+
122+
return async_to_sync(_post_process_request)(request, response)
123+
124+
return wraps(view_func)(_view_wrapper)
125+
126+
return _decorator
127+
128+
return _make_decorator

0 commit comments

Comments
 (0)