[Django] #37065: @method_decorator can't be used on async view at class-level with name="dispatch"

52 views
Skip to first unread message

Django

unread,
Apr 24, 2026, 3:42:44 PMApr 24
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Type: Bug
Status: new | Component: Utilities
Version: 5.2 | Severity: Normal
Keywords: async | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
`@method_decorator(..., name="dispatch")` doesn't work for async views
that don't override `dispatch()`, because `dispatch()` is sync, which is
enough to fool the logic in #35083.


{{{#!diff
diff --git a/tests/decorators/test_cache.py
b/tests/decorators/test_cache.py
index 1aca6967e0..c3b1668a7c 100644
--- a/tests/decorators/test_cache.py
+++ b/tests/decorators/test_cache.py
@@ -1,3 +1,4 @@
+from http import HTTPStatus
from inspect import iscoroutinefunction
from unittest import mock

@@ -5,6 +6,7 @@ from django.http import HttpRequest, HttpResponse
from django.test import SimpleTestCase
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_control, cache_page,
never_cache
+from django.views.generic import View


class HttpRequestProxy:
@@ -217,6 +219,17 @@ class NeverCacheDecoratorTest(SimpleTestCase):
with self.assertRaisesMessage(TypeError, msg):
await MyClass().async_view(HttpRequestProxy(request))

+ async def
test_never_cache_method_decorator_http_request_async_view(self):
+ @method_decorator(never_cache, name="dispatch")
+ class MyClass(View):
+ async def get(self, request):
+ return HttpResponse()
+
+ request = HttpRequest()
+ request.method = "GET"
+ response = await MyClass().dispatch(request)
+ self.assertEqual(response.status_code, HTTPStatus.OK)
+
def test_never_cache_decorator_http_request_proxy(self):
class MyClass:
@method_decorator(never_cache)
}}}
{{{#!py
ERROR: test_never_cache_method_decorator_http_request_async_view
(decorators.test_cache.NeverCacheDecoratorTest.test_never_cache_method_decorator_http_request_async_view)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jwalls/my314/lib/python3.14/site-packages/asgiref/sync.py",
line 325, in __call__
return call_result.result()
~~~~~~~~~~~~~~~~~~^^
File
"/Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/concurrent/futures/_base.py",
line 443, in result
return self.__get_result()
~~~~~~~~~~~~~~~~~^^
File
"/Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/concurrent/futures/_base.py",
line 395, in __get_result
raise self._exception
File "/Users/jwalls/my314/lib/python3.14/site-packages/asgiref/sync.py",
line 365, in main_wrap
result = await awaitable
^^^^^^^^^^^^^^^
File "/Users/jwalls/django/tests/decorators/test_cache.py", line 230, in
test_never_cache_method_decorator_http_request_async_view
response = await MyClass().dispatch(request)
~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "/Users/jwalls/django/django/utils/decorators.py", line 47, in
_wrapper
return bound_method(*args, **kwargs)
File "/Users/jwalls/django/django/views/decorators/cache.py", line 80,
in _view_wrapper
add_never_cache_headers(response)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
File "/Users/jwalls/django/django/utils/cache.py", line 294, in
add_never_cache_headers
patch_response_headers(response, cache_timeout=-1)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jwalls/django/django/utils/cache.py", line 285, in
patch_response_headers
if not response.has_header("Expires"):
^^^^^^^^^^^^^^^^^^^
AttributeError: 'coroutine' object has no attribute 'has_header'
}}}

----
Moving the decorator to the method instead of the class works. We probably
will prefer a test inside the test class added in #35083 rather than
merging my sketched test.
--
Ticket URL: <https://code.djangoproject.com/ticket/37065>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Apr 27, 2026, 6:30:35 AMApr 27
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Utilities | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Changes (by Vishy Algo):

* owner: (none) => Vishy Algo
* status: new => assigned

--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:1>

Django

unread,
Apr 27, 2026, 7:43:45 AMApr 27
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Utilities | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Changes (by Sarah Boyce):

* stage: Unreviewed => Accepted

--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:2>

Django

unread,
May 10, 2026, 11:32:48 AMMay 10
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Utilities | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Changes (by Vishy Algo):

* has_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:3>

Django

unread,
May 11, 2026, 6:19:48 AMMay 11
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Utilities | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Changes (by JaeHyuckSa):

* needs_better_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:4>

Django

unread,
May 15, 2026, 6:41:58 AMMay 15
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Utilities | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Comment (by Vishy Algo):

Hi Jacob,

Please take a look at the PR and let me know whether patching `View` with
`__init_subclass__` would be an appropriate fix, or if it would be
considered out of scope for this ticket.
--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:5>

Django

unread,
May 15, 2026, 11:25:49 AMMay 15
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Utilities | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Changes (by Carlton Gibson):

* cc: Carlton Gibson (added)

--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:6>

Django

unread,
May 15, 2026, 12:38:15 PMMay 15
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Utilities | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Comment (by Carlton Gibson):

This is a doozy. I'm not convinced it's tractable... (at reasonable
cost/complexity to method_decorator).

If the method being decorated is not async then it's not 100% clear to me
that method_decorator should do **any** further introspection to determine
if the return value should be marked as a coroutine.

We're asking it to decorate a method, and #35083 was about allowing those
methods to be async. Both conjuncts work.

> Moving the decorator to the method instead of the class works.

A further ''know significant details about the particulars of View''
strikes me as out of scope for method_decorator.

If I **had to** decorate `dispatch` for an async view class, I think this
is probably the best option:


{{{
@method_decorator(never_cache, name="dispatch")
class MyClass(View):
async def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)

async def get(self, request):
return HttpResponse()
}}}

(Not tested. You get the idea)

This somewhat mitigates using the `name="dispatch"` — so I'd probably put
it on the method directly, and I'd only need to do ''that'' if we also had
say `async def post` as well.

But I think trying to automagically our way forward here is mistake. It's
complex. It just is.

So I think a docs tweak is probably the way to go.
--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:7>

Django

unread,
May 15, 2026, 2:06:12 PMMay 15
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Utilities | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Comment (by Vishy Algo):

I completely agree, inspecting the return value and patching feels more
like over-engineering than necessary.

But would `async get dispatch` cause any issues, if handled incorrectly!
Cause, when just overriding dispatch (without http methods) also seems to
be a mistake.

Probably `as_view` should also be overridden (again when all http methods
are sync, **view_is_async** is False).
--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:8>

Django

unread,
May 15, 2026, 3:27:11 PMMay 15
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Utilities | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Comment (by Carlton Gibson):

It makes no sense to override dispatch to be async except in this case.
--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:9>

Django

unread,
May 16, 2026, 8:25:27 AMMay 16
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-----------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Utilities | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------------+--------------------------------------
Changes (by Carlton Gibson):

* needs_better_patch: 1 => 0

Comment:

I added a proposal for a docs example in
[https://github.com/django/django/pull/21292 PR]. Will adjust flags for a
review.
--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:10>

Django

unread,
May 16, 2026, 9:52:01 AMMay 16
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-------------------------------+--------------------------------------
Reporter: Jacob Walls | Owner: Vishy Algo
Type: Bug | Status: assigned
Component: Documentation | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by Jacob Walls):

* component: Utilities => Documentation

Comment:

Thanks, Carlton, that looks great. As you might have guessed, I dashed
this off while debugging some tests, unfortunately just bewitched by the
mental model that ''this recipe works for decorating the whole class''
without thinking about `method_decorator`'s responsibility. As you well
point out, we're just missing some docs. Thanks Vishy for the discussion.
--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:11>

Django

unread,
May 26, 2026, 4:00:27 PMMay 26
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: Vishy
Type: Bug | Status: assigned
Component: Documentation | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Jacob Walls):

* stage: Accepted => Ready for checkin

--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:12>

Django

unread,
May 26, 2026, 4:00:34 PMMay 26
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: Carlton
| Gibson
Type: Bug | Status: assigned
Component: Documentation | Version: 5.2
Severity: Normal | Resolution:
Keywords: async | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Jacob Walls):

* owner: Vishy => Carlton Gibson

--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:13>

Django

unread,
May 27, 2026, 9:36:59 AMMay 27
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: Carlton
| Gibson
Type: Bug | Status: closed
Component: Documentation | Version: 5.2
Severity: Normal | Resolution: fixed
Keywords: async | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Jacob Walls <jacobtylerwalls@…>):

* resolution: => fixed
* status: assigned => closed

Comment:

In [changeset:"41357f42c52ff7677af3d93b59b0aa6574b0ac19" 41357f42]:
{{{#!CommitTicketReference repository=""
revision="41357f42c52ff7677af3d93b59b0aa6574b0ac19"
Fixed #37065 -- Doc'd method_decorator usage on dispatch for async views.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:14>

Django

unread,
May 27, 2026, 9:37:39 AMMay 27
to django-...@googlegroups.com
#37065: @method_decorator can't be used on async view at class-level with
name="dispatch"
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Owner: Carlton
| Gibson
Type: Bug | Status: closed
Component: Documentation | Version: 5.2
Severity: Normal | Resolution: fixed
Keywords: async | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Jacob Walls <jacobtylerwalls@…>):

In [changeset:"9d9443e6fdadea948da4a6741778ee3d44667f89" 9d9443e6]:
{{{#!CommitTicketReference repository=""
revision="9d9443e6fdadea948da4a6741778ee3d44667f89"
[6.1.x] Fixed #37065 -- Doc'd method_decorator usage on dispatch for async
views.

Backport of 41357f42c52ff7677af3d93b59b0aa6574b0ac19 from main.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/37065#comment:15>
Reply all
Reply to author
Forward
0 new messages