1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Fixed #31061 -- Ignored positional args in django.urls.resolve() when all optional named parameters are missing.

Regression in 76b993a117.

Thanks Claude Paroz for the report and Carlton Gibson for reviews.
This commit is contained in:
Mariusz Felisiak 2019-12-06 09:32:51 +01:00 committed by GitHub
parent f138e75910
commit 82a88d2f48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 22 additions and 2 deletions

View File

@ -158,8 +158,9 @@ class RegexPattern(CheckURLMixin):
# If there are any named groups, use those as kwargs, ignoring
# non-named groups. Otherwise, pass all non-named arguments as
# 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()
kwargs = {k: v for k, v in kwargs.items() if v is not None}
return path[match.end():], args, kwargs
return None

View File

@ -13,3 +13,7 @@ Bugfixes
inside Jupyter and other environments that force an async context, by adding
and option to disable :ref:`async-safety` mechanism with
``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`).

View File

@ -53,7 +53,7 @@ algorithm the system follows to determine which Python code to execute:
arguments:
* 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.
* The keyword arguments are made up of any named parts matched by the
path expression, overridden by any arguments specified in the optional

View File

@ -12,6 +12,11 @@ urlpatterns = [
path('included_urls/', include('urlpatterns.included_urls')),
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_only_optional/(?:(?P<arg1>\d+)/)?',
views.empty_view,
name='regex_only_optional',
),
path('', include('urlpatterns.more_urls')),
path('<lang>/<path:url>/', views.empty_view, name='lang-and-path'),
]

View File

@ -68,6 +68,16 @@ class SimplifiedURLTests(SimpleTestCase):
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):
match = resolve('/included_urls/extra/something/')
self.assertEqual(match.url_name, 'inner-extra')