Fixed #32195 -- Added system check for invalid view in path() and improved error messages.
This commit is contained in:
parent
8f89454bbc
commit
3e73c65ffc
|
@ -55,6 +55,8 @@ def include(arg, namespace=None):
|
|||
|
||||
|
||||
def _path(route, view, kwargs=None, name=None, Pattern=None):
|
||||
from django.views import View
|
||||
|
||||
if isinstance(view, (list, tuple)):
|
||||
# For include(...) processing.
|
||||
pattern = Pattern(route, is_endpoint=False)
|
||||
|
@ -69,6 +71,12 @@ def _path(route, view, kwargs=None, name=None, Pattern=None):
|
|||
elif callable(view):
|
||||
pattern = Pattern(route, name=name, is_endpoint=True)
|
||||
return URLPattern(pattern, view, kwargs, name)
|
||||
elif isinstance(view, View):
|
||||
view_cls_name = view.__class__.__name__
|
||||
raise TypeError(
|
||||
f'view must be a callable, pass {view_cls_name}.as_view(), not '
|
||||
f'{view_cls_name}().'
|
||||
)
|
||||
else:
|
||||
raise TypeError('view must be a callable or a list/tuple in the case of include().')
|
||||
|
||||
|
|
|
@ -345,6 +345,7 @@ class URLPattern:
|
|||
def check(self):
|
||||
warnings = self._check_pattern_name()
|
||||
warnings.extend(self.pattern.check())
|
||||
warnings.extend(self._check_callback())
|
||||
return warnings
|
||||
|
||||
def _check_pattern_name(self):
|
||||
|
@ -361,6 +362,22 @@ class URLPattern:
|
|||
else:
|
||||
return []
|
||||
|
||||
def _check_callback(self):
|
||||
from django.views import View
|
||||
|
||||
view = self.callback
|
||||
if inspect.isclass(view) and issubclass(view, View):
|
||||
return [Error(
|
||||
'Your URL pattern %s has an invalid view, pass %s.as_view() '
|
||||
'instead of %s.' % (
|
||||
self.pattern.describe(),
|
||||
view.__name__,
|
||||
view.__name__,
|
||||
),
|
||||
id='urls.E009',
|
||||
)]
|
||||
return []
|
||||
|
||||
def resolve(self, path):
|
||||
match = self.pattern.match(path)
|
||||
if match:
|
||||
|
|
|
@ -584,6 +584,8 @@ The following checks are performed on your URL configuration:
|
|||
take the correct number of arguments (…).
|
||||
* **urls.E008**: The custom ``handlerXXX`` view ``'path.to.view'`` could not be
|
||||
imported.
|
||||
* **urls.E009**: Your URL pattern ``<pattern>`` has an invalid view, pass
|
||||
``<view>.as_view()`` instead of ``<view>``.
|
||||
|
||||
``contrib`` app checks
|
||||
======================
|
||||
|
|
|
@ -134,6 +134,16 @@ class CheckUrlConfigTests(SimpleTestCase):
|
|||
result = check_url_namespaces_unique(None)
|
||||
self.assertEqual(result, [])
|
||||
|
||||
@override_settings(ROOT_URLCONF='check_framework.urls.cbv_as_view')
|
||||
def test_check_view_not_class(self):
|
||||
self.assertEqual(check_url_config(None), [
|
||||
Error(
|
||||
"Your URL pattern 'missing_as_view' has an invalid view, pass "
|
||||
"EmptyCBV.as_view() instead of EmptyCBV.",
|
||||
id='urls.E009',
|
||||
),
|
||||
])
|
||||
|
||||
|
||||
class UpdatedToPathTests(SimpleTestCase):
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
from django.http import HttpResponse
|
||||
from django.urls import path
|
||||
from django.views import View
|
||||
|
||||
|
||||
class EmptyCBV(View):
|
||||
pass
|
||||
|
||||
|
||||
class EmptyCallableView:
|
||||
def __call__(self, request, *args, **kwargs):
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('missing_as_view', EmptyCBV),
|
||||
path('has_as_view', EmptyCBV.as_view()),
|
||||
path('callable_class', EmptyCallableView()),
|
||||
]
|
|
@ -5,6 +5,7 @@ from django.core.exceptions import ImproperlyConfigured
|
|||
from django.test import SimpleTestCase
|
||||
from django.test.utils import override_settings
|
||||
from django.urls import NoReverseMatch, Resolver404, path, resolve, reverse
|
||||
from django.views import View
|
||||
|
||||
from .converters import DynamicConverter
|
||||
from .views import empty_view
|
||||
|
@ -146,6 +147,14 @@ class SimplifiedURLTests(SimpleTestCase):
|
|||
with self.assertRaisesMessage(TypeError, msg):
|
||||
path('articles/', 'invalid_view')
|
||||
|
||||
def test_invalid_view_instance(self):
|
||||
class EmptyCBV(View):
|
||||
pass
|
||||
|
||||
msg = 'view must be a callable, pass EmptyCBV.as_view(), not EmptyCBV().'
|
||||
with self.assertRaisesMessage(TypeError, msg):
|
||||
path('foo', EmptyCBV())
|
||||
|
||||
def test_whitespace_in_route(self):
|
||||
msg = (
|
||||
"URL route 'space/<int:num>/extra/<str:%stest>' cannot contain "
|
||||
|
|
Loading…
Reference in New Issue