Refs #31949 -- Made @csrf_exempt decorator to work with async functions.
This commit is contained in:
parent
6d427288e4
commit
953f81e078
@ -1,5 +1,7 @@
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
|
from asgiref.sync import iscoroutinefunction
|
||||||
|
|
||||||
from django.middleware.csrf import CsrfViewMiddleware, get_token
|
from django.middleware.csrf import CsrfViewMiddleware, get_token
|
||||||
from django.utils.decorators import decorator_from_middleware
|
from django.utils.decorators import decorator_from_middleware
|
||||||
|
|
||||||
@ -51,9 +53,17 @@ def csrf_exempt(view_func):
|
|||||||
|
|
||||||
# view_func.csrf_exempt = True would also work, but decorators are nicer
|
# view_func.csrf_exempt = True would also work, but decorators are nicer
|
||||||
# if they don't have side effects, so return a new function.
|
# if they don't have side effects, so return a new function.
|
||||||
@wraps(view_func)
|
|
||||||
def wrapper_view(*args, **kwargs):
|
|
||||||
return view_func(*args, **kwargs)
|
|
||||||
|
|
||||||
wrapper_view.csrf_exempt = True
|
if iscoroutinefunction(view_func):
|
||||||
return wrapper_view
|
|
||||||
|
async def _view_wrapper(request, *args, **kwargs):
|
||||||
|
return await view_func(request, *args, **kwargs)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
def _view_wrapper(request, *args, **kwargs):
|
||||||
|
return view_func(request, *args, **kwargs)
|
||||||
|
|
||||||
|
_view_wrapper.csrf_exempt = True
|
||||||
|
|
||||||
|
return wraps(view_func)(_view_wrapper)
|
||||||
|
@ -150,6 +150,10 @@ class-based views<decorating-class-based-views>`.
|
|||||||
def my_view(request):
|
def my_view(request):
|
||||||
return HttpResponse("Hello world")
|
return HttpResponse("Hello world")
|
||||||
|
|
||||||
|
.. versionchanged:: 5.0
|
||||||
|
|
||||||
|
Support for wrapping asynchronous view functions was added.
|
||||||
|
|
||||||
.. function:: csrf_protect(view)
|
.. function:: csrf_protect(view)
|
||||||
|
|
||||||
Decorator that provides the protection of ``CsrfViewMiddleware`` to a view.
|
Decorator that provides the protection of ``CsrfViewMiddleware`` to a view.
|
||||||
|
@ -258,6 +258,7 @@ Decorators
|
|||||||
* :func:`~django.views.decorators.cache.cache_control`
|
* :func:`~django.views.decorators.cache.cache_control`
|
||||||
* :func:`~django.views.decorators.cache.never_cache`
|
* :func:`~django.views.decorators.cache.never_cache`
|
||||||
* :func:`~django.views.decorators.common.no_append_slash`
|
* :func:`~django.views.decorators.common.no_append_slash`
|
||||||
|
* :func:`~django.views.decorators.csrf.csrf_exempt`
|
||||||
* :func:`~django.views.decorators.debug.sensitive_variables`
|
* :func:`~django.views.decorators.debug.sensitive_variables`
|
||||||
* :func:`~django.views.decorators.debug.sensitive_post_parameters`
|
* :func:`~django.views.decorators.debug.sensitive_post_parameters`
|
||||||
* :func:`~django.views.decorators.http.condition`
|
* :func:`~django.views.decorators.http.condition`
|
||||||
|
@ -84,6 +84,7 @@ view functions:
|
|||||||
* :func:`~django.views.decorators.cache.cache_control`
|
* :func:`~django.views.decorators.cache.cache_control`
|
||||||
* :func:`~django.views.decorators.cache.never_cache`
|
* :func:`~django.views.decorators.cache.never_cache`
|
||||||
* :func:`~django.views.decorators.common.no_append_slash`
|
* :func:`~django.views.decorators.common.no_append_slash`
|
||||||
|
* :func:`~django.views.decorators.csrf.csrf_exempt`
|
||||||
* :func:`~django.views.decorators.http.condition`
|
* :func:`~django.views.decorators.http.condition`
|
||||||
* :func:`~django.views.decorators.http.etag`
|
* :func:`~django.views.decorators.http.etag`
|
||||||
* :func:`~django.views.decorators.http.last_modified`
|
* :func:`~django.views.decorators.http.last_modified`
|
||||||
|
37
tests/decorators/test_csrf.py
Normal file
37
tests/decorators/test_csrf.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from asgiref.sync import iscoroutinefunction
|
||||||
|
|
||||||
|
from django.http import HttpRequest, HttpResponse
|
||||||
|
from django.test import SimpleTestCase
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
|
|
||||||
|
class CsrfExemptTests(SimpleTestCase):
|
||||||
|
def test_wrapped_sync_function_is_not_coroutine_function(self):
|
||||||
|
def sync_view(request):
|
||||||
|
return HttpResponse()
|
||||||
|
|
||||||
|
wrapped_view = csrf_exempt(sync_view)
|
||||||
|
self.assertIs(iscoroutinefunction(wrapped_view), False)
|
||||||
|
|
||||||
|
def test_wrapped_async_function_is_coroutine_function(self):
|
||||||
|
async def async_view(request):
|
||||||
|
return HttpResponse()
|
||||||
|
|
||||||
|
wrapped_view = csrf_exempt(async_view)
|
||||||
|
self.assertIs(iscoroutinefunction(wrapped_view), True)
|
||||||
|
|
||||||
|
def test_csrf_exempt_decorator(self):
|
||||||
|
@csrf_exempt
|
||||||
|
def sync_view(request):
|
||||||
|
return HttpResponse()
|
||||||
|
|
||||||
|
self.assertIs(sync_view.csrf_exempt, True)
|
||||||
|
self.assertIsInstance(sync_view(HttpRequest()), HttpResponse)
|
||||||
|
|
||||||
|
async def test_csrf_exempt_decorator_async_view(self):
|
||||||
|
@csrf_exempt
|
||||||
|
async def async_view(request):
|
||||||
|
return HttpResponse()
|
||||||
|
|
||||||
|
self.assertIs(async_view.csrf_exempt, True)
|
||||||
|
self.assertIsInstance(await async_view(HttpRequest()), HttpResponse)
|
Loading…
x
Reference in New Issue
Block a user