﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
37065	"@method_decorator can't be used on async view at class-level with name=""dispatch"""	Jacob Walls		"`@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."	Bug	new	Utilities	5.2	Normal		async		Unreviewed	0	0	0	0	0	0
