diff --git a/django/views/generic/simple.py b/django/views/generic/simple.py index 0e1e6b083a..c3cf407163 100644 --- a/django/views/generic/simple.py +++ b/django/views/generic/simple.py @@ -49,12 +49,16 @@ def redirect_to(request, url, permanent=True, query_string=False, **kwargs): """ args = request.META.get('QUERY_STRING', '') - if args and query_string and url is not None: - url = "%s?%s" % (url, args) if url is not None: + if kwargs: + url = url % kwargs + + if args and query_string: + url = "%s?%s" % (url, args) + klass = permanent and HttpResponsePermanentRedirect or HttpResponseRedirect - return klass(url % kwargs) + return klass(url) else: logger.warning('Gone: %s' % request.path, extra={ diff --git a/tests/regressiontests/views/generic_urls.py b/tests/regressiontests/views/generic_urls.py index 2d7a203cab..40a6c012ff 100644 --- a/tests/regressiontests/views/generic_urls.py +++ b/tests/regressiontests/views/generic_urls.py @@ -115,4 +115,5 @@ urlpatterns += patterns('django.views.generic.simple', (r'^simple/redirect_to_none/$', 'redirect_to', dict(url=None)), (r'^simple/redirect_to_arg/(?P\d+)/$', 'redirect_to', dict(url='/simple/target_arg/%(id)s/')), (r'^simple/redirect_to_query/$', 'redirect_to', dict(url='/simple/target/', query_string=True)), + (r'^simple/redirect_to_arg_and_query/(?P\d+)/$', 'redirect_to', dict(url='/simple/target_arg/%(id)s/', query_string=True)), ) diff --git a/tests/regressiontests/views/tests/generic/simple.py b/tests/regressiontests/views/tests/generic/simple.py index be54af9185..7dcf08a032 100644 --- a/tests/regressiontests/views/tests/generic/simple.py +++ b/tests/regressiontests/views/tests/generic/simple.py @@ -48,9 +48,17 @@ class RedirectToTest(TestCase): self.assertEqual(response.status_code, 301) self.assertEqual('http://testserver/simple/target/?param1=foo¶m2=bar', response['Location']) + # Confirm that the contents of the query string are not subject to + # string interpolation (Refs #17111): + response = self.client.get('/simple/redirect_to_query/?param1=foo¶m2=hist%C3%B3ria') + self.assertEqual(response.status_code, 301) + self.assertEqual('http://testserver/simple/target/?param1=foo¶m2=hist%C3%B3ria', response['Location']) + response = self.client.get('/simple/redirect_to_arg_and_query/99/?param1=foo¶m2=hist%C3%B3ria') + self.assertEqual(response.status_code, 301) + self.assertEqual('http://testserver/simple/target_arg/99/?param1=foo¶m2=hist%C3%B3ria', response['Location']) + def test_redirect_to_when_meta_contains_no_query_string(self): "regression for #16705" # we can't use self.client.get because it always sets QUERY_STRING response = self.client.request(PATH_INFO='/simple/redirect_to/') self.assertEqual(response.status_code, 301) -