diff --git a/django/middleware/common.py b/django/middleware/common.py index fb55412c9b..4dd2e14652 100644 --- a/django/middleware/common.py +++ b/django/middleware/common.py @@ -85,7 +85,7 @@ class CommonMiddleware(object): new_url[0], urlquote(new_url[1])) else: newurl = urlquote(new_url[1]) - if request.GET: + if request.META.get('QUERY_STRING', ''): newurl += '?' + request.META['QUERY_STRING'] return http.HttpResponsePermanentRedirect(newurl) diff --git a/django/test/client.py b/django/test/client.py index e143c748b9..a5ef075f3c 100644 --- a/django/test/client.py +++ b/django/test/client.py @@ -182,18 +182,18 @@ class RequestFactory(object): """ The base environment for a request. """ + # This is a minimal valid WSGI environ dictionary, plus HTTP_COOKIE + # for cookie support. Empty strings are omitted. + # See http://www.python.org/dev/peps/pep-3333/#environ-variables environ = { 'HTTP_COOKIE': self.cookies.output(header='', sep='; '), - 'PATH_INFO': '/', - 'QUERY_STRING': '', - 'REMOTE_ADDR': '127.0.0.1', 'REQUEST_METHOD': 'GET', - 'SCRIPT_NAME': '', 'SERVER_NAME': 'testserver', 'SERVER_PORT': '80', 'SERVER_PROTOCOL': 'HTTP/1.1', 'wsgi.version': (1,0), 'wsgi.url_scheme': 'http', + 'wsgi.input': FakePayload(''), 'wsgi.errors': self.errors, 'wsgi.multiprocess': True, 'wsgi.multithread': False, @@ -235,7 +235,6 @@ class RequestFactory(object): 'PATH_INFO': self._get_path(parsed), 'QUERY_STRING': urlencode(data, doseq=True) or parsed[4], 'REQUEST_METHOD': 'GET', - 'wsgi.input': FakePayload('') } r.update(extra) return self.request(**r) @@ -267,7 +266,6 @@ class RequestFactory(object): 'PATH_INFO': self._get_path(parsed), 'QUERY_STRING': urlencode(data, doseq=True) or parsed[4], 'REQUEST_METHOD': 'HEAD', - 'wsgi.input': FakePayload('') } r.update(extra) return self.request(**r) @@ -280,7 +278,6 @@ class RequestFactory(object): 'PATH_INFO': self._get_path(parsed), 'QUERY_STRING': urlencode(data, doseq=True) or parsed[4], 'REQUEST_METHOD': 'OPTIONS', - 'wsgi.input': FakePayload('') } r.update(extra) return self.request(**r) @@ -311,7 +308,6 @@ class RequestFactory(object): 'PATH_INFO': self._get_path(parsed), 'QUERY_STRING': urlencode(data, doseq=True) or parsed[4], 'REQUEST_METHOD': 'DELETE', - 'wsgi.input': FakePayload('') } r.update(extra) return self.request(**r) diff --git a/django/views/generic/base.py b/django/views/generic/base.py index f2d495021d..ea14281a71 100644 --- a/django/views/generic/base.py +++ b/django/views/generic/base.py @@ -140,7 +140,7 @@ class RedirectView(View): are provided as kwargs to this method. """ if self.url: - args = self.request.META["QUERY_STRING"] + args = self.request.META.get('QUERY_STRING', '') if args and self.query_string: url = "%s?%s" % (self.url, args) else: diff --git a/django/views/generic/simple.py b/django/views/generic/simple.py index 26df504c2b..0e1e6b083a 100644 --- a/django/views/generic/simple.py +++ b/django/views/generic/simple.py @@ -48,7 +48,7 @@ def redirect_to(request, url, permanent=True, query_string=False, **kwargs): from the request is appended to the URL. """ - args = request.META["QUERY_STRING"] + args = request.META.get('QUERY_STRING', '') if args and query_string and url is not None: url = "%s?%s" % (url, args) diff --git a/tests/regressiontests/generic_views/base.py b/tests/regressiontests/generic_views/base.py index 40490a421c..00fa0d9b79 100644 --- a/tests/regressiontests/generic_views/base.py +++ b/tests/regressiontests/generic_views/base.py @@ -248,7 +248,7 @@ class RedirectViewTest(unittest.TestCase): response = RedirectView.as_view()(self.rf.get('/foo/')) self.assertEqual(response.status_code, 410) - def test_permanaent_redirect(self): + def test_permanent_redirect(self): "Default is a permanent redirect" response = RedirectView.as_view(url='/bar/')(self.rf.get('/foo/')) self.assertEqual(response.status_code, 301) @@ -305,3 +305,9 @@ class RedirectViewTest(unittest.TestCase): response = RedirectView.as_view(url='/bar/')(self.rf.delete('/foo/')) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], '/bar/') + + def test_redirect_when_meta_contains_no_query_string(self): + "regression for #16705" + # we can't use self.rf.get because it always sets QUERY_STRING + response = RedirectView.as_view(url='/bar/')(self.rf.request(PATH_INFO='/foo/')) + self.assertEqual(response.status_code, 301) diff --git a/tests/regressiontests/views/tests/generic/simple.py b/tests/regressiontests/views/tests/generic/simple.py index 6bf6f50832..be54af9185 100644 --- a/tests/regressiontests/views/tests/generic/simple.py +++ b/tests/regressiontests/views/tests/generic/simple.py @@ -47,3 +47,10 @@ class RedirectToTest(TestCase): response = self.client.get('/simple/redirect_to_query/?param1=foo¶m2=bar') self.assertEqual(response.status_code, 301) self.assertEqual('http://testserver/simple/target/?param1=foo¶m2=bar', 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) +