diff options
author | Antoine Lorence <contact@alorence.me> | 2022-09-29 12:10:02 +0200 |
---|---|---|
committer | Carlton Gibson <carlton@noumenal.es> | 2022-09-29 16:28:44 +0200 |
commit | 9b0c9821ed4dd9920cc7c5e7b657720d91a89bdc (patch) | |
tree | a812dd5f173c0080c3e49d7306511f82ab4d193d | |
parent | 19e6efa50b603af325e7f62058364f278596758f (diff) | |
download | django-9b0c9821ed4dd9920cc7c5e7b657720d91a89bdc.tar.gz |
Fixed #34062 -- Updated View.http_method_not_allowed() to support async.
As with the options() methods, wrap the response in a coroutine if
the view is async.
Co-authored-by: Carlton Gibson <carlton.gibson@noumenal.es>
-rw-r--r-- | django/views/generic/base.py | 11 | ||||
-rw-r--r-- | docs/releases/4.1.2.txt | 4 | ||||
-rw-r--r-- | tests/async/tests.py | 23 |
3 files changed, 35 insertions, 3 deletions
diff --git a/django/views/generic/base.py b/django/views/generic/base.py index db1842e3e5..3a3afb0c73 100644 --- a/django/views/generic/base.py +++ b/django/views/generic/base.py @@ -148,7 +148,16 @@ class View: request.path, extra={"status_code": 405, "request": request}, ) - return HttpResponseNotAllowed(self._allowed_methods()) + response = HttpResponseNotAllowed(self._allowed_methods()) + + if self.view_is_async: + + async def func(): + return response + + return func() + else: + return response def options(self, request, *args, **kwargs): """Handle responding to requests for the OPTIONS HTTP verb.""" diff --git a/docs/releases/4.1.2.txt b/docs/releases/4.1.2.txt index 57b0b6c6e8..d607c34c92 100644 --- a/docs/releases/4.1.2.txt +++ b/docs/releases/4.1.2.txt @@ -39,3 +39,7 @@ Bugfixes * Fixed a regression in Django 4.1 that didn't alter a sequence type when altering type of pre-Django 4.1 serial columns on PostgreSQL (:ticket:`34058`). + +* Fixed a regression in Django 4.1 that caused a crash for :class:`View` + subclasses with asynchronous handlers when handling non-allowed HTTP methods + (:ticket:`34062`). diff --git a/tests/async/tests.py b/tests/async/tests.py index 66eece4b97..559f21b8b1 100644 --- a/tests/async/tests.py +++ b/tests/async/tests.py @@ -6,8 +6,8 @@ from asgiref.sync import async_to_sync from django.core.cache import DEFAULT_CACHE_ALIAS, caches from django.core.exceptions import ImproperlyConfigured, SynchronousOnlyOperation -from django.http import HttpResponse -from django.test import SimpleTestCase +from django.http import HttpResponse, HttpResponseNotAllowed +from django.test import RequestFactory, SimpleTestCase from django.utils.asyncio import async_unsafe from django.views.generic.base import View @@ -119,6 +119,25 @@ class ViewTests(SimpleTestCase): self.assertIsInstance(response, HttpResponse) + def test_http_method_not_allowed_responds_correctly(self): + request_factory = RequestFactory() + tests = [ + (SyncView, False), + (AsyncView, True), + ] + for view_cls, is_coroutine in tests: + with self.subTest(view_cls=view_cls, is_coroutine=is_coroutine): + instance = view_cls() + response = instance.http_method_not_allowed(request_factory.post("/")) + self.assertIs( + asyncio.iscoroutine(response), + is_coroutine, + ) + if is_coroutine: + response = asyncio.run(response) + + self.assertIsInstance(response, HttpResponseNotAllowed) + def test_base_view_class_is_sync(self): """ View and by extension any subclasses that don't define handlers are |