Skip to content

Commit 7c947f0

Browse files
lothemarfelixxm
authored andcommitted
Fixed #31494 -- Preserved query strings when following HTTP 307/308 redirects in test client.
1 parent 6425fd3 commit 7c947f0

File tree

3 files changed

+23
-2
lines changed

3 files changed

+23
-2
lines changed

django/test/client.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -826,8 +826,12 @@ def _handle_redirects(self, response, data='', content_type='', **extra):
826826
path = urljoin(response.request['PATH_INFO'], path)
827827

828828
if response.status_code in (HTTPStatus.TEMPORARY_REDIRECT, HTTPStatus.PERMANENT_REDIRECT):
829-
# Preserve request method post-redirect for 307/308 responses.
830-
request_method = getattr(self, response.request['REQUEST_METHOD'].lower())
829+
# Preserve request method and query string (if needed)
830+
# post-redirect for 307/308 responses.
831+
request_method = response.request['REQUEST_METHOD'].lower()
832+
if request_method not in ('get', 'head'):
833+
extra['QUERY_STRING'] = url.query
834+
request_method = getattr(self, request_method)
831835
else:
832836
request_method = self.get
833837
data = QueryDict(url.query)

docs/releases/3.2.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ Tests
214214
creating deep copies with :py:func:`copy.deepcopy`. Assigning objects which
215215
don't support ``deepcopy()`` is deprecated and will be removed in Django 4.1.
216216

217+
* :class:`~django.test.Client` now preserves the request query string when
218+
following 307 and 308 redirects.
219+
217220
URLs
218221
~~~~
219222

tests/test_client/tests.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,20 @@ def test_follow_307_and_308_redirect(self):
284284
self.assertEqual(response.request['PATH_INFO'], '/post_view/')
285285
self.assertEqual(response.request['REQUEST_METHOD'], method.upper())
286286

287+
def test_follow_307_and_308_preserves_query_string(self):
288+
methods = ('post', 'options', 'put', 'patch', 'delete', 'trace')
289+
codes = (307, 308)
290+
for method, code in itertools.product(methods, codes):
291+
with self.subTest(method=method, code=code):
292+
req_method = getattr(self.client, method)
293+
response = req_method(
294+
'/redirect_view_%s_query_string/' % code,
295+
data={'value': 'test'},
296+
follow=True,
297+
)
298+
self.assertRedirects(response, '/post_view/?hello=world', status_code=code)
299+
self.assertEqual(response.request['QUERY_STRING'], 'hello=world')
300+
287301
def test_follow_307_and_308_get_head_query_string(self):
288302
methods = ('get', 'head')
289303
codes = (307, 308)

0 commit comments

Comments
 (0)