Commit 6e13c049 authored by Tim Graham's avatar Tim Graham
Browse files

Changed RedirectView.permanent to False per deprecation timeline; refs #21587.

parent bd98926f
Loading
Loading
Loading
Loading
+1 −29
Original line number Diff line number Diff line
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
+4 −4
Original line number Diff line number Diff line
@@ -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

+29 −90
Original line number Diff line number Diff line
@@ -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):
+2 −2
Original line number Diff line number Diff line
@@ -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),
+19 −19
Original line number Diff line number Diff line
@@ -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')
Loading