Commits

Anonymous committed 5d5ed6a

Fixed #17111 -- Made the `redirect_to` generic view properly handle query strings with percent symbols. Thanks, Chris Adams.

Comments (0)

Files changed (3)

django/views/generic/simple.py

 
     """
     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={

tests/regressiontests/views/generic_urls.py

     (r'^simple/redirect_to_none/$', 'redirect_to', dict(url=None)),
     (r'^simple/redirect_to_arg/(?P<id>\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<id>\d+)/$', 'redirect_to', dict(url='/simple/target_arg/%(id)s/', query_string=True)),
 )

tests/regressiontests/views/tests/generic/simple.py

         self.assertEqual(response.status_code, 301)
         self.assertEqual('http://testserver/simple/target/?param1=foo&param2=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&param2=hist%C3%B3ria')
+        self.assertEqual(response.status_code, 301)
+        self.assertEqual('http://testserver/simple/target/?param1=foo&param2=hist%C3%B3ria', response['Location'])
+        response = self.client.get('/simple/redirect_to_arg_and_query/99/?param1=foo&param2=hist%C3%B3ria')
+        self.assertEqual(response.status_code, 301)
+        self.assertEqual('http://testserver/simple/target_arg/99/?param1=foo&param2=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)
-