diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index e8d6a46c689..ffe74bc6505 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -388,7 +388,7 @@ class RegexURLResolver(LocaleRegexProvider): if len(args) != len(params) + len(prefix_args): continue unicode_args = [force_text(val) for val in args] - candidate = (prefix_norm + result) % dict(zip(prefix_args + params, unicode_args)) + candidate = (prefix_norm.replace('%', '%%') + result) % dict(zip(prefix_args + params, unicode_args)) else: if set(kwargs.keys()) | set(defaults.keys()) != set(params) | set(defaults.keys()) | set(prefix_args): continue diff --git a/tests/urlpatterns_reverse/tests.py b/tests/urlpatterns_reverse/tests.py index 8dc21e4bc98..1860c9dd2c9 100644 --- a/tests/urlpatterns_reverse/tests.py +++ b/tests/urlpatterns_reverse/tests.py @@ -183,6 +183,11 @@ class URLPatternReverse(TestCase): self.assertEqual('/bump%2520map/includes/non_path_include/', reverse('non_path_include', prefix='/bump%20map/')) + def test_non_urlsafe_prefix_with_args(self): + # Regression for #20022 + self.assertEqual('/%7Eme/places/1/', + reverse('places', args=[1], prefix='/~me/')) + class ResolverTests(unittest.TestCase): def test_resolver_repr(self): """