summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2019-12-06 09:32:51 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-12-06 09:33:45 +0100
commite986e49e66c23c26012749e1a134cba1d6d0bfdd (patch)
treea4fc936f764a24e06be15915ce194fe4eff8156b
parent6ede5a3cb7ae92d6d8fdbd71805fb4742c672dd9 (diff)
[3.0.x] Fixed #31061 -- Ignored positional args in django.urls.resolve() when all optional named parameters are missing.
Regression in 76b993a117b61c41584e95149a67d8a1e9f49dd1. Thanks Claude Paroz for the report and Carlton Gibson for reviews. Backport of 82a88d2f48e13ef5d472741d5ed1c183230cfe4c from master
-rw-r--r--django/urls/resolvers.py3
-rw-r--r--docs/releases/3.0.1.txt4
-rw-r--r--docs/topics/http/urls.txt2
-rw-r--r--tests/urlpatterns/path_urls.py5
-rw-r--r--tests/urlpatterns/tests.py10
5 files changed, 22 insertions, 2 deletions
diff --git a/django/urls/resolvers.py b/django/urls/resolvers.py
index 2ff8b2c775..19d0d98986 100644
--- a/django/urls/resolvers.py
+++ b/django/urls/resolvers.py
@@ -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
diff --git a/docs/releases/3.0.1.txt b/docs/releases/3.0.1.txt
index 589ef40499..cdfdc33e40 100644
--- a/docs/releases/3.0.1.txt
+++ b/docs/releases/3.0.1.txt
@@ -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`).
diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt
index 4283d6ebe1..5c1540b809 100644
--- a/docs/topics/http/urls.txt
+++ b/docs/topics/http/urls.txt
@@ -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
diff --git a/tests/urlpatterns/path_urls.py b/tests/urlpatterns/path_urls.py
index b40801b39d..afc15f30af 100644
--- a/tests/urlpatterns/path_urls.py
+++ b/tests/urlpatterns/path_urls.py
@@ -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'),
]
diff --git a/tests/urlpatterns/tests.py b/tests/urlpatterns/tests.py
index 92c4e6399e..b149e0d512 100644
--- a/tests/urlpatterns/tests.py
+++ b/tests/urlpatterns/tests.py
@@ -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')