[3.0.x] Fixed #31061 -- Ignored positional args in django.urls.resolve() when all optional named parameters are missing.
Regression in76b993a117
. Thanks Claude Paroz for the report and Carlton Gibson for reviews. Backport of82a88d2f48
from master
This commit is contained in:
parent
6ede5a3cb7
commit
e986e49e66
|
@ -158,8 +158,9 @@ class RegexPattern(CheckURLMixin):
|
||||||
# If there are any named groups, use those as kwargs, ignoring
|
# If there are any named groups, use those as kwargs, ignoring
|
||||||
# non-named groups. Otherwise, pass all non-named arguments as
|
# non-named groups. Otherwise, pass all non-named arguments as
|
||||||
# positional arguments.
|
# positional arguments.
|
||||||
kwargs = {k: v for k, v in match.groupdict().items() if v is not None}
|
kwargs = match.groupdict()
|
||||||
args = () if kwargs else match.groups()
|
args = () if kwargs else match.groups()
|
||||||
|
kwargs = {k: v for k, v in kwargs.items() if v is not None}
|
||||||
return path[match.end():], args, kwargs
|
return path[match.end():], args, kwargs
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -13,3 +13,7 @@ Bugfixes
|
||||||
inside Jupyter and other environments that force an async context, by adding
|
inside Jupyter and other environments that force an async context, by adding
|
||||||
and option to disable :ref:`async-safety` mechanism with
|
and option to disable :ref:`async-safety` mechanism with
|
||||||
``DJANGO_ALLOW_ASYNC_UNSAFE`` environment variable (:ticket:`31056`).
|
``DJANGO_ALLOW_ASYNC_UNSAFE`` environment variable (:ticket:`31056`).
|
||||||
|
|
||||||
|
* Fixed a regression in Django 3.0 where ``RegexPattern``, used by
|
||||||
|
:func:`~django.urls.re_path`, returned positional arguments to be passed to
|
||||||
|
the view when all optional named groups were missing (:ticket:`31061`).
|
||||||
|
|
|
@ -53,7 +53,7 @@ algorithm the system follows to determine which Python code to execute:
|
||||||
arguments:
|
arguments:
|
||||||
|
|
||||||
* An instance of :class:`~django.http.HttpRequest`.
|
* An instance of :class:`~django.http.HttpRequest`.
|
||||||
* If the matched URL pattern returned no named groups, then the
|
* If the matched URL pattern contained no named groups, then the
|
||||||
matches from the regular expression are provided as positional arguments.
|
matches from the regular expression are provided as positional arguments.
|
||||||
* The keyword arguments are made up of any named parts matched by the
|
* The keyword arguments are made up of any named parts matched by the
|
||||||
path expression, overridden by any arguments specified in the optional
|
path expression, overridden by any arguments specified in the optional
|
||||||
|
|
|
@ -12,6 +12,11 @@ urlpatterns = [
|
||||||
path('included_urls/', include('urlpatterns.included_urls')),
|
path('included_urls/', include('urlpatterns.included_urls')),
|
||||||
re_path(r'^regex/(?P<pk>[0-9]+)/$', views.empty_view, name='regex'),
|
re_path(r'^regex/(?P<pk>[0-9]+)/$', views.empty_view, name='regex'),
|
||||||
re_path(r'^regex_optional/(?P<arg1>\d+)/(?:(?P<arg2>\d+)/)?', views.empty_view, name='regex_optional'),
|
re_path(r'^regex_optional/(?P<arg1>\d+)/(?:(?P<arg2>\d+)/)?', views.empty_view, name='regex_optional'),
|
||||||
|
re_path(
|
||||||
|
r'^regex_only_optional/(?:(?P<arg1>\d+)/)?',
|
||||||
|
views.empty_view,
|
||||||
|
name='regex_only_optional',
|
||||||
|
),
|
||||||
path('', include('urlpatterns.more_urls')),
|
path('', include('urlpatterns.more_urls')),
|
||||||
path('<lang>/<path:url>/', views.empty_view, name='lang-and-path'),
|
path('<lang>/<path:url>/', views.empty_view, name='lang-and-path'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -68,6 +68,16 @@ class SimplifiedURLTests(SimpleTestCase):
|
||||||
r'^regex_optional/(?P<arg1>\d+)/(?:(?P<arg2>\d+)/)?',
|
r'^regex_optional/(?P<arg1>\d+)/(?:(?P<arg2>\d+)/)?',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_re_path_with_missing_optional_parameter(self):
|
||||||
|
match = resolve('/regex_only_optional/')
|
||||||
|
self.assertEqual(match.url_name, 'regex_only_optional')
|
||||||
|
self.assertEqual(match.kwargs, {})
|
||||||
|
self.assertEqual(match.args, ())
|
||||||
|
self.assertEqual(
|
||||||
|
match.route,
|
||||||
|
r'^regex_only_optional/(?:(?P<arg1>\d+)/)?',
|
||||||
|
)
|
||||||
|
|
||||||
def test_path_lookup_with_inclusion(self):
|
def test_path_lookup_with_inclusion(self):
|
||||||
match = resolve('/included_urls/extra/something/')
|
match = resolve('/included_urls/extra/something/')
|
||||||
self.assertEqual(match.url_name, 'inner-extra')
|
self.assertEqual(match.url_name, 'inner-extra')
|
||||||
|
|
Loading…
Reference in New Issue