Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions django/views/generic/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ class RedirectView(View):
url = None
pattern_name = None
query_string = False
preserve_request = False

def get_redirect_url(self, *args, **kwargs):
"""
Expand All @@ -261,9 +262,11 @@ def get(self, request, *args, **kwargs):
url = self.get_redirect_url(*args, **kwargs)
if url:
if self.permanent:
return HttpResponsePermanentRedirect(url)
return HttpResponsePermanentRedirect(
url, preserve_request=self.preserve_request
)
else:
return HttpResponseRedirect(url)
return HttpResponseRedirect(url, preserve_request=self.preserve_request)
else:
response = HttpResponseGone()
log_response("Gone: %s", request.path, response=response, request=request)
Expand Down
9 changes: 9 additions & 0 deletions docs/ref/class-based-views/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,15 @@ ancestor classes are documented under the section title of **Ancestors
then the query string is discarded. By default, ``query_string`` is
``False``.

.. attribute:: preserve_request

.. versionadded:: 6.1

Whether to preserve the HTTP method and body during the redirect. If
``True``, then the redirect will use status code 307 instead of 302,
or 308 instead of 301 when :attr:`permanent` is ``True``. By default,
``preserve_request`` is ``False``.

**Methods**

.. method:: get_redirect_url(*args, **kwargs)
Expand Down
4 changes: 3 additions & 1 deletion docs/releases/6.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,9 @@ Forms
Generic Views
~~~~~~~~~~~~~

* ...
* The new :attr:`.RedirectView.preserve_request` attribute allows preserving
the HTTP method and body during redirects, using 307/308 status codes instead
of 302/301.

Internationalization
~~~~~~~~~~~~~~~~~~~~
Expand Down
14 changes: 14 additions & 0 deletions tests/generic_views/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,20 @@ def test_temporary_redirect(self):
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/bar/")

def test_preserve_request_temporary_redirect(self):
response = RedirectView.as_view(url="/bar/", preserve_request=True)(
self.rf.get("/foo/")
)
self.assertEqual(response.status_code, 307)
self.assertEqual(response.url, "/bar/")

def test_preserve_request_permanent_redirect(self):
response = RedirectView.as_view(
url="/bar/", preserve_request=True, permanent=True
)(self.rf.get("/foo/"))
self.assertEqual(response.status_code, 308)
self.assertEqual(response.url, "/bar/")

def test_include_args(self):
"GET arguments can be included in the redirected URL"
response = RedirectView.as_view(url="/bar/")(self.rf.get("/foo/"))
Expand Down
2 changes: 1 addition & 1 deletion tests/requirements/py3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pymemcache >= 3.4.0
pywatchman; sys_platform != 'win32'
PyYAML >= 6.0.2
redis >= 5.1.0
selenium >= 4.23.0
selenium >= 4.23.0,<4.44.0
sqlparse >= 0.5.0
tblib >= 3.0.0
tzdata
Expand Down
Loading