diff --git a/django/views/generic/base.py b/django/views/generic/base.py index e9aac357f41..a873f11f054 100644 --- a/django/views/generic/base.py +++ b/django/views/generic/base.py @@ -1,7 +1,6 @@ from __future__ import unicode_literals import logging -import warnings from functools import update_wrapper from django import http @@ -9,10 +8,8 @@ from django.core.exceptions import ImproperlyConfigured from django.core.urlresolvers import reverse, NoReverseMatch from django.template.response import TemplateResponse from django.utils.decorators import classonlymethod -from django.utils.deprecation import RemovedInDjango19Warning from django.utils import six -_sentinel = object() logger = logging.getLogger('django.request') @@ -163,36 +160,11 @@ class RedirectView(View): """ A view that provides a redirect on any GET request. """ - permanent = _sentinel + permanent = False url = None pattern_name = None query_string = False - def __init__(self, *args, **kwargs): - if 'permanent' not in kwargs and self.permanent is _sentinel: - warnings.warn( - "Default value of 'RedirectView.permanent' will change " - "from True to False in Django 1.9. Set an explicit value " - "to silence this warning.", - RemovedInDjango19Warning, - stacklevel=2 - ) - self.permanent = True - super(RedirectView, self).__init__(*args, **kwargs) - - @classonlymethod - def as_view(cls, **initkwargs): - if 'permanent' not in initkwargs and cls.permanent is _sentinel: - warnings.warn( - "Default value of 'RedirectView.permanent' will change " - "from True to False in Django 1.9. Set an explicit value " - "to silence this warning.", - RemovedInDjango19Warning, - stacklevel=2 - ) - initkwargs['permanent'] = True - return super(RedirectView, cls).as_view(**initkwargs) - def get_redirect_url(self, *args, **kwargs): """ Return the URL redirect to. Keyword arguments from the diff --git a/docs/ref/class-based-views/base.txt b/docs/ref/class-based-views/base.txt index 2c90cd48931..0b599895359 100644 --- a/docs/ref/class-based-views/base.txt +++ b/docs/ref/class-based-views/base.txt @@ -225,12 +225,12 @@ RedirectView Whether the redirect should be permanent. The only difference here is the HTTP status code returned. If ``True``, then the redirect will use status code 301. If ``False``, then the redirect will use status code - 302. By default, ``permanent`` is ``True``. + 302. By default, ``permanent`` is ``False``. - .. deprecated:: 1.8 + .. versionchanged:: 1.9 - The default value of the ``permanent`` attribute will change from - ``True`` to ``False`` in Django 1.9. + The default value of the ``permanent`` attribute changed from + ``True`` to ``False``. .. attribute:: query_string diff --git a/tests/generic_views/test_base.py b/tests/generic_views/test_base.py index ce3a0f52d68..47518fdd925 100644 --- a/tests/generic_views/test_base.py +++ b/tests/generic_views/test_base.py @@ -2,14 +2,11 @@ from __future__ import unicode_literals import time import unittest -import warnings from django.core.exceptions import ImproperlyConfigured from django.core.urlresolvers import resolve from django.http import HttpResponse -from django.utils import six -from django.utils.deprecation import RemovedInDjango19Warning -from django.test import TestCase, RequestFactory, ignore_warnings, override_settings +from django.test import TestCase, RequestFactory, override_settings from django.views.generic import View, TemplateView, RedirectView from . import views @@ -340,7 +337,6 @@ class TemplateViewTest(TestCase): self.assertIs(match.func.view_class, TemplateView) -@ignore_warnings(category=RemovedInDjango19Warning) @override_settings(ROOT_URLCONF='generic_views.urls') class RedirectViewTest(TestCase): @@ -351,14 +347,20 @@ class RedirectViewTest(TestCase): response = RedirectView.as_view()(self.rf.get('/foo/')) self.assertEqual(response.status_code, 410) - def test_permanent_redirect(self): - "Default is a permanent redirect" + def test_default_redirect(self): + "Default is a temporary redirect" response = RedirectView.as_view(url='/bar/')(self.rf.get('/foo/')) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, '/bar/') + + def test_permanent_redirect(self): + "Permanent redirects are an option" + response = RedirectView.as_view(url='/bar/', permanent=True)(self.rf.get('/foo/')) self.assertEqual(response.status_code, 301) self.assertEqual(response.url, '/bar/') def test_temporary_redirect(self): - "Permanent redirects are an option" + "Temporary redirects are an option" response = RedirectView.as_view(url='/bar/', permanent=False)(self.rf.get('/foo/')) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/bar/') @@ -366,35 +368,35 @@ class RedirectViewTest(TestCase): def test_include_args(self): "GET arguments can be included in the redirected URL" response = RedirectView.as_view(url='/bar/')(self.rf.get('/foo/')) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/bar/') response = RedirectView.as_view(url='/bar/', query_string=True)(self.rf.get('/foo/?pork=spam')) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/bar/?pork=spam') def test_include_urlencoded_args(self): "GET arguments can be URL-encoded when included in the redirected URL" response = RedirectView.as_view(url='/bar/', query_string=True)( self.rf.get('/foo/?unicode=%E2%9C%93')) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/bar/?unicode=%E2%9C%93') def test_parameter_substitution(self): "Redirection URLs can be parameterized" response = RedirectView.as_view(url='/bar/%(object_id)d/')(self.rf.get('/foo/42/'), object_id=42) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/bar/42/') def test_named_url_pattern(self): "Named pattern parameter should reverse to the matching pattern" response = RedirectView.as_view(pattern_name='artist_detail')(self.rf.get('/foo/'), pk=1) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response['Location'], '/detail/artist/1/') def test_named_url_pattern_using_args(self): response = RedirectView.as_view(pattern_name='artist_detail')(self.rf.get('/foo/'), 1) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response['Location'], '/detail/artist/1/') def test_wrong_named_url_pattern(self): @@ -403,46 +405,46 @@ class RedirectViewTest(TestCase): self.assertEqual(response.status_code, 410) def test_redirect_POST(self): - "Default is a permanent redirect" + "Default is a temporary redirect" response = RedirectView.as_view(url='/bar/')(self.rf.post('/foo/')) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/bar/') def test_redirect_HEAD(self): - "Default is a permanent redirect" + "Default is a temporary redirect" response = RedirectView.as_view(url='/bar/')(self.rf.head('/foo/')) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/bar/') def test_redirect_OPTIONS(self): - "Default is a permanent redirect" + "Default is a temporary redirect" response = RedirectView.as_view(url='/bar/')(self.rf.options('/foo/')) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/bar/') def test_redirect_PUT(self): - "Default is a permanent redirect" + "Default is a temporary redirect" response = RedirectView.as_view(url='/bar/')(self.rf.put('/foo/')) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/bar/') def test_redirect_PATCH(self): - "Default is a permanent redirect" + "Default is a temporary redirect" response = RedirectView.as_view(url='/bar/')(self.rf.patch('/foo/')) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/bar/') def test_redirect_DELETE(self): - "Default is a permanent redirect" + "Default is a temporary redirect" response = RedirectView.as_view(url='/bar/')(self.rf.delete('/foo/')) - self.assertEqual(response.status_code, 301) + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, '/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) + self.assertEqual(response.status_code, 302) def test_direct_instantiation(self): """ @@ -454,69 +456,6 @@ class RedirectViewTest(TestCase): self.assertEqual(response.status_code, 410) -@override_settings(ROOT_URLCONF='generic_views.urls') -class RedirectViewDeprecationTest(TestCase): - - rf = RequestFactory() - - def test_deprecation_warning_init(self): - with warnings.catch_warnings(record=True) as warns: - warnings.simplefilter('always') - - view = RedirectView() - response = view.dispatch(self.rf.head('/python/')) - - self.assertEqual(response.status_code, 410) - self.assertEqual(len(warns), 1) - self.assertIs(warns[0].category, RemovedInDjango19Warning) - self.assertEqual( - six.text_type(warns[0].message), - "Default value of 'RedirectView.permanent' will change " - "from True to False in Django 1.9. Set an explicit value " - "to silence this warning.", - ) - - def test_deprecation_warning_raised_when_permanent_not_passed(self): - with warnings.catch_warnings(record=True) as warns: - warnings.simplefilter('always') - - view_function = RedirectView.as_view(url='/bbb/') - request = self.rf.request(PATH_INFO='/aaa/') - view_function(request) - - self.assertEqual(len(warns), 1) - self.assertIs(warns[0].category, RemovedInDjango19Warning) - self.assertEqual( - six.text_type(warns[0].message), - "Default value of 'RedirectView.permanent' will change " - "from True to False in Django 1.9. Set an explicit value " - "to silence this warning.", - ) - - def test_no_deprecation_warning_when_permanent_passed(self): - with warnings.catch_warnings(record=True) as warns: - warnings.simplefilter('always') - - view_function = RedirectView.as_view(url='/bar/', permanent=False) - request = self.rf.request(PATH_INFO='/foo/') - view_function(request) - - self.assertEqual(len(warns), 0) - - def test_no_deprecation_warning_with_custom_redirectview(self): - class CustomRedirectView(RedirectView): - permanent = False - - with warnings.catch_warnings(record=True) as warns: - warnings.simplefilter('always') - - view_function = CustomRedirectView.as_view(url='/eggs/') - request = self.rf.request(PATH_INFO='/spam/') - view_function(request) - - self.assertEqual(len(warns), 0) - - class GetContextDataTest(unittest.TestCase): def test_get_context_data_super(self): diff --git a/tests/test_client/urls.py b/tests/test_client/urls.py index 45d2859633c..72fe9676ee0 100644 --- a/tests/test_client/urls.py +++ b/tests/test_client/urls.py @@ -15,8 +15,8 @@ urlpatterns = [ url(r'^secure_view/$', views.view_with_secure), url(r'^permanent_redirect_view/$', RedirectView.as_view(url='/get_view/', permanent=True)), url(r'^temporary_redirect_view/$', RedirectView.as_view(url='/get_view/', permanent=False)), - url(r'^http_redirect_view/$', RedirectView.as_view(url='/secure_view/', permanent=True)), - url(r'^https_redirect_view/$', RedirectView.as_view(url='https://testserver/secure_view/', permanent=True)), + url(r'^http_redirect_view/$', RedirectView.as_view(url='/secure_view/')), + url(r'^https_redirect_view/$', RedirectView.as_view(url='https://testserver/secure_view/')), url(r'^double_redirect_view/$', views.double_redirect_view), url(r'^bad_view/$', views.bad_view), url(r'^form_view/$', views.form_view), diff --git a/tests/test_client_regress/tests.py b/tests/test_client_regress/tests.py index 1ae94573002..43a2298017b 100644 --- a/tests/test_client_regress/tests.py +++ b/tests/test_client_regress/tests.py @@ -353,27 +353,27 @@ class AssertRedirectsTests(TestCase): "You can follow a redirect chain of multiple redirects" response = self.client.get('/redirects/further/more/', {}, follow=True) self.assertRedirects(response, '/no_template_view/', - status_code=301, target_status_code=200) + status_code=302, target_status_code=200) self.assertEqual(len(response.redirect_chain), 1) - self.assertEqual(response.redirect_chain[0], ('http://testserver/no_template_view/', 301)) + self.assertEqual(response.redirect_chain[0], ('http://testserver/no_template_view/', 302)) def test_multiple_redirect_chain(self): "You can follow a redirect chain of multiple redirects" response = self.client.get('/redirects/', {}, follow=True) self.assertRedirects(response, '/no_template_view/', - status_code=301, target_status_code=200) + status_code=302, target_status_code=200) self.assertEqual(len(response.redirect_chain), 3) - self.assertEqual(response.redirect_chain[0], ('http://testserver/redirects/further/', 301)) - self.assertEqual(response.redirect_chain[1], ('http://testserver/redirects/further/more/', 301)) - self.assertEqual(response.redirect_chain[2], ('http://testserver/no_template_view/', 301)) + self.assertEqual(response.redirect_chain[0], ('http://testserver/redirects/further/', 302)) + self.assertEqual(response.redirect_chain[1], ('http://testserver/redirects/further/more/', 302)) + self.assertEqual(response.redirect_chain[2], ('http://testserver/no_template_view/', 302)) def test_redirect_chain_to_non_existent(self): "You can follow a chain to a non-existent view" response = self.client.get('/redirect_to_non_existent_view2/', {}, follow=True) self.assertRedirects(response, '/non_existent_view/', - status_code=301, target_status_code=404) + status_code=302, target_status_code=404) def test_redirect_chain_to_self(self): "Redirections to self are caught and escaped" @@ -382,7 +382,7 @@ class AssertRedirectsTests(TestCase): response = context.exception.last_response # The chain of redirects stops once the cycle is detected. self.assertRedirects(response, '/redirect_to_self/', - status_code=301, target_status_code=301) + status_code=302, target_status_code=302) self.assertEqual(len(response.redirect_chain), 2) def test_redirect_to_self_with_changing_query(self): @@ -397,7 +397,7 @@ class AssertRedirectsTests(TestCase): response = context.exception.last_response # The chain of redirects will get back to the starting point, but stop there. self.assertRedirects(response, '/circular_redirect_2/', - status_code=301, target_status_code=301) + status_code=302, target_status_code=302) self.assertEqual(len(response.redirect_chain), 4) def test_redirect_chain_post(self): @@ -405,7 +405,7 @@ class AssertRedirectsTests(TestCase): response = self.client.post('/redirects/', {'nothing': 'to_send'}, follow=True) self.assertRedirects(response, - '/no_template_view/', 301, 200) + '/no_template_view/', 302, 200) self.assertEqual(len(response.redirect_chain), 3) def test_redirect_chain_head(self): @@ -413,7 +413,7 @@ class AssertRedirectsTests(TestCase): response = self.client.head('/redirects/', {'nothing': 'to_send'}, follow=True) self.assertRedirects(response, - '/no_template_view/', 301, 200) + '/no_template_view/', 302, 200) self.assertEqual(len(response.redirect_chain), 3) def test_redirect_chain_options(self): @@ -421,7 +421,7 @@ class AssertRedirectsTests(TestCase): response = self.client.options('/redirects/', follow=True) self.assertRedirects(response, - '/no_template_view/', 301, 200) + '/no_template_view/', 302, 200) self.assertEqual(len(response.redirect_chain), 3) def test_redirect_chain_put(self): @@ -429,7 +429,7 @@ class AssertRedirectsTests(TestCase): response = self.client.put('/redirects/', follow=True) self.assertRedirects(response, - '/no_template_view/', 301, 200) + '/no_template_view/', 302, 200) self.assertEqual(len(response.redirect_chain), 3) def test_redirect_chain_delete(self): @@ -437,7 +437,7 @@ class AssertRedirectsTests(TestCase): response = self.client.delete('/redirects/', follow=True) self.assertRedirects(response, - '/no_template_view/', 301, 200) + '/no_template_view/', 302, 200) self.assertEqual(len(response.redirect_chain), 3) def test_redirect_to_different_host(self): @@ -445,7 +445,7 @@ class AssertRedirectsTests(TestCase): response = self.client.get('/redirect_other_host/', follow=True) self.assertRedirects(response, 'https://otherserver:8443/no_template_view/', - status_code=301, target_status_code=200) + status_code=302, target_status_code=200) # We can't use is_secure() or get_host() # because response.request is a dictionary, not an HttpRequest self.assertEqual(response.request.get('wsgi.url_scheme'), 'https') @@ -492,11 +492,11 @@ class AssertRedirectsTests(TestCase): # always redirects to https response = self.client.get('/https_redirect_view/', follow=follow, secure=secure) # no scheme to compare too, always succeeds - self.assertRedirects(response, '/secure_view/', status_code=301) + self.assertRedirects(response, '/secure_view/', status_code=302) # the goal scheme is https - self.assertRedirects(response, 'https://testserver/secure_view/', status_code=301) + self.assertRedirects(response, 'https://testserver/secure_view/', status_code=302) with self.assertRaises(AssertionError): - self.assertRedirects(response, 'http://testserver/secure_view/', status_code=301) + self.assertRedirects(response, 'http://testserver/secure_view/', status_code=302) @override_settings(ROOT_URLCONF='test_client_regress.urls') @@ -1369,7 +1369,7 @@ class RequestHeadersTest(TestCase): response = self.client.get("/check_headers_redirect/", follow=True, HTTP_X_ARG_CHECK='Testing 123') self.assertEqual(response.content, b"HTTP_X_ARG_CHECK: Testing 123") self.assertRedirects(response, '/check_headers/', - status_code=301, target_status_code=200) + status_code=302, target_status_code=200) @override_settings(ROOT_URLCONF='test_client_regress.urls') diff --git a/tests/test_client_regress/urls.py b/tests/test_client_regress/urls.py index 8914c829024..a69a774555d 100644 --- a/tests/test_client_regress/urls.py +++ b/tests/test_client_regress/urls.py @@ -3,7 +3,7 @@ from django.views.generic import RedirectView from . import views -# TODO: Remove permanent=True where it doesn't matter in Django 1.9 + urlpatterns = [ url(r'', include('test_client.urls')), @@ -15,17 +15,17 @@ urlpatterns = [ url(r'^arg_view/(?P.+)/$', views.view_with_argument, name='arg_view'), url(r'^nested_view/$', views.nested_view, name='nested_view'), url(r'^login_protected_redirect_view/$', views.login_protected_redirect_view), - url(r'^redirects/$', RedirectView.as_view(url='/redirects/further/', permanent=True)), - url(r'^redirects/further/$', RedirectView.as_view(url='/redirects/further/more/', permanent=True)), - url(r'^redirects/further/more/$', RedirectView.as_view(url='/no_template_view/', permanent=True)), - url(r'^redirect_to_non_existent_view/$', RedirectView.as_view(url='/non_existent_view/', permanent=True)), - url(r'^redirect_to_non_existent_view2/$', RedirectView.as_view(url='/redirect_to_non_existent_view/', permanent=True)), - url(r'^redirect_to_self/$', RedirectView.as_view(url='/redirect_to_self/', permanent=True)), + url(r'^redirects/$', RedirectView.as_view(url='/redirects/further/')), + url(r'^redirects/further/$', RedirectView.as_view(url='/redirects/further/more/')), + url(r'^redirects/further/more/$', RedirectView.as_view(url='/no_template_view/')), + url(r'^redirect_to_non_existent_view/$', RedirectView.as_view(url='/non_existent_view/')), + url(r'^redirect_to_non_existent_view2/$', RedirectView.as_view(url='/redirect_to_non_existent_view/')), + url(r'^redirect_to_self/$', RedirectView.as_view(url='/redirect_to_self/')), url(r'^redirect_to_self_with_changing_query_view/$', views.redirect_to_self_with_changing_query_view), - url(r'^circular_redirect_1/$', RedirectView.as_view(url='/circular_redirect_2/', permanent=True)), - url(r'^circular_redirect_2/$', RedirectView.as_view(url='/circular_redirect_3/', permanent=True)), - url(r'^circular_redirect_3/$', RedirectView.as_view(url='/circular_redirect_1/', permanent=True)), - url(r'^redirect_other_host/$', RedirectView.as_view(url='https://otherserver:8443/no_template_view/', permanent=True)), + url(r'^circular_redirect_1/$', RedirectView.as_view(url='/circular_redirect_2/')), + url(r'^circular_redirect_2/$', RedirectView.as_view(url='/circular_redirect_3/')), + url(r'^circular_redirect_3/$', RedirectView.as_view(url='/circular_redirect_1/')), + url(r'^redirect_other_host/$', RedirectView.as_view(url='https://otherserver:8443/no_template_view/')), url(r'^set_session/$', views.set_session_view), url(r'^check_session/$', views.check_session_view), url(r'^request_methods/$', views.request_methods_view), @@ -33,7 +33,7 @@ urlpatterns = [ url(r'^check_binary/$', views.return_undecodable_binary), url(r'^parse_unicode_json/$', views.return_json_file), url(r'^check_headers/$', views.check_headers), - url(r'^check_headers_redirect/$', RedirectView.as_view(url='/check_headers/', permanent=True)), + url(r'^check_headers_redirect/$', RedirectView.as_view(url='/check_headers/')), url(r'^body/$', views.body), url(r'^read_all/$', views.read_all), url(r'^read_buffer/$', views.read_buffer), diff --git a/tests/urlpatterns_reverse/reverse_lazy_urls.py b/tests/urlpatterns_reverse/reverse_lazy_urls.py index 76ff67b2c08..57358f62541 100644 --- a/tests/urlpatterns_reverse/reverse_lazy_urls.py +++ b/tests/urlpatterns_reverse/reverse_lazy_urls.py @@ -6,6 +6,5 @@ urlpatterns = [ url(r'^redirected_to/$', empty_view, name='named-lazy-url-redirected-to'), url(r'^login/$', empty_view, name='some-login-page'), url(r'^login_required_view/$', login_required_view), - # TODO: Remove permanent=True where it doesn't matter in Django 1.9 - url(r'^redirect/$', LazyRedirectView.as_view(permanent=True)), + url(r'^redirect/$', LazyRedirectView.as_view()), ] diff --git a/tests/urlpatterns_reverse/tests.py b/tests/urlpatterns_reverse/tests.py index a9dffdc1628..310250152f8 100644 --- a/tests/urlpatterns_reverse/tests.py +++ b/tests/urlpatterns_reverse/tests.py @@ -308,7 +308,7 @@ class ReverseLazyTest(TestCase): def test_redirect_with_lazy_reverse(self): response = self.client.get('/redirect/') - self.assertRedirects(response, "/redirected_to/", status_code=301) + self.assertRedirects(response, "/redirected_to/", status_code=302) def test_user_permission_with_lazy_reverse(self): User.objects.create_user('alfred', 'alfred@example.com', password='testpw')