Fixed #18659 -- Deprecated request.REQUEST and MergeDict

Thanks Aymeric Augustin for the suggestion.
This commit is contained in:
Bouke Haarsma 2013-10-15 22:36:49 +02:00 committed by Tim Graham
parent 98788d3c3a
commit 2fb5a51fa3
14 changed files with 87 additions and 21 deletions

View File

@ -1284,8 +1284,10 @@ class ModelAdmin(BaseModelAdmin):
context = dict(self.admin_site.each_context(), context = dict(self.admin_site.each_context(),
title=_('Add %s') % force_text(opts.verbose_name), title=_('Add %s') % force_text(opts.verbose_name),
adminform=adminForm, adminform=adminForm,
is_popup=IS_POPUP_VAR in request.REQUEST, is_popup=(IS_POPUP_VAR in request.POST or
to_field=request.REQUEST.get(TO_FIELD_VAR), IS_POPUP_VAR in request.GET),
to_field=request.POST.get(TO_FIELD_VAR,
request.GET.get(TO_FIELD_VAR)),
media=media, media=media,
inline_admin_formsets=inline_admin_formsets, inline_admin_formsets=inline_admin_formsets,
errors=helpers.AdminErrorList(form, formsets), errors=helpers.AdminErrorList(form, formsets),
@ -1357,8 +1359,10 @@ class ModelAdmin(BaseModelAdmin):
adminform=adminForm, adminform=adminForm,
object_id=object_id, object_id=object_id,
original=obj, original=obj,
is_popup=IS_POPUP_VAR in request.REQUEST, is_popup=(IS_POPUP_VAR in request.POST or
to_field=request.REQUEST.get(TO_FIELD_VAR), IS_POPUP_VAR in request.GET),
to_field=request.POST.get(TO_FIELD_VAR,
request.GET.get(TO_FIELD_VAR)),
media=media, media=media,
inline_admin_formsets=inline_admin_formsets, inline_admin_formsets=inline_admin_formsets,
errors=helpers.AdminErrorList(form, formsets), errors=helpers.AdminErrorList(form, formsets),

View File

@ -144,7 +144,8 @@ class UserAdmin(admin.ModelAdmin):
'adminForm': adminForm, 'adminForm': adminForm,
'form_url': form_url, 'form_url': form_url,
'form': form, 'form': form,
'is_popup': IS_POPUP_VAR in request.REQUEST, 'is_popup': (IS_POPUP_VAR in request.POST or
IS_POPUP_VAR in request.GET),
'add': True, 'add': True,
'change': False, 'change': False,
'has_delete_permission': False, 'has_delete_permission': False,

View File

@ -526,7 +526,6 @@ class LoginTest(AuthViewsTestCase):
req.COOKIES[settings.CSRF_COOKIE_NAME] = token1 req.COOKIES[settings.CSRF_COOKIE_NAME] = token1
req.method = "POST" req.method = "POST"
req.POST = {'username': 'testclient', 'password': password, 'csrfmiddlewaretoken': token1} req.POST = {'username': 'testclient', 'password': password, 'csrfmiddlewaretoken': token1}
req.REQUEST = req.POST
# Use POST request to log in # Use POST request to log in
SessionMiddleware().process_request(req) SessionMiddleware().process_request(req)

View File

@ -28,7 +28,8 @@ def login(request, template_name='registration/login.html',
""" """
Displays the login form and handles the login action. Displays the login form and handles the login action.
""" """
redirect_to = request.REQUEST.get(redirect_field_name, '') redirect_to = request.POST.get(redirect_field_name,
request.GET.get(redirect_field_name, ''))
if request.method == "POST": if request.method == "POST":
form = authentication_form(request, data=request.POST) form = authentication_form(request, data=request.POST)
@ -71,8 +72,10 @@ def logout(request, next_page=None,
if next_page is not None: if next_page is not None:
next_page = resolve_url(next_page) next_page = resolve_url(next_page)
if redirect_field_name in request.REQUEST: if (redirect_field_name in request.POST or
next_page = request.REQUEST[redirect_field_name] redirect_field_name in request.GET):
next_page = request.POST.get(redirect_field_name,
request.GET.get(redirect_field_name))
# Security check -- don't allow redirection to a different host. # Security check -- don't allow redirection to a different host.
if not is_safe_url(url=next_page, host=request.get_host()): if not is_safe_url(url=next_page, host=request.get_host()):
next_page = request.path next_page = request.path

View File

@ -5,6 +5,7 @@ import logging
import sys import sys
from io import BytesIO from io import BytesIO
from threading import Lock from threading import Lock
import warnings
from django import http from django import http
from django.conf import settings from django.conf import settings
@ -129,6 +130,8 @@ class WSGIRequest(http.HttpRequest):
return content_type, content_params return content_type, content_params
def _get_request(self): def _get_request(self):
warnings.warn('`request.REQUEST` is deprecated, use `request.GET` or '
'`request.POST` instead.', PendingDeprecationWarning, 2)
if not hasattr(self, '_request'): if not hasattr(self, '_request'):
self._request = datastructures.MergeDict(self.POST, self.GET) self._request = datastructures.MergeDict(self.POST, self.GET)
return self._request return self._request

View File

@ -12,6 +12,8 @@ class MergeDict(object):
first occurrence will be used. first occurrence will be used.
""" """
def __init__(self, *dicts): def __init__(self, *dicts):
warnings.warn('`MergeDict` is deprecated, use `dict.update()` '
'instead.', PendingDeprecationWarning, 2)
self.dicts = dicts self.dicts = dicts
def __bool__(self): def __bool__(self):

View File

@ -24,7 +24,7 @@ def set_language(request):
redirect to the page in the request (the 'next' parameter) without changing redirect to the page in the request (the 'next' parameter) without changing
any state. any state.
""" """
next = request.REQUEST.get('next') next = request.POST.get('next', request.GET.get('next'))
if not is_safe_url(url=next, host=request.get_host()): if not is_safe_url(url=next, host=request.get_host()):
next = request.META.get('HTTP_REFERER') next = request.META.get('HTTP_REFERER')
if not is_safe_url(url=next, host=request.get_host()): if not is_safe_url(url=next, host=request.get_host()):

View File

@ -469,6 +469,10 @@ these changes.
* ``django.forms.get_declared_fields`` will be removed. * ``django.forms.get_declared_fields`` will be removed.
* The ``WSGIRequest.REQUEST`` property will be removed.
* The class ``django.utils.datastructures.MergeDict`` will be removed.
2.0 2.0
--- ---

View File

@ -110,6 +110,9 @@ All attributes should be considered read-only, unless stated otherwise below.
.. attribute:: HttpRequest.REQUEST .. attribute:: HttpRequest.REQUEST
.. deprecated:: 1.7
Use the more explicit ``GET`` and ``POST`` instead.
For convenience, a dictionary-like object that searches ``POST`` first, For convenience, a dictionary-like object that searches ``POST`` first,
then ``GET``. Inspired by PHP's ``$_REQUEST``. then ``GET``. Inspired by PHP's ``$_REQUEST``.

View File

@ -639,3 +639,18 @@ deprecated. Use :djadminopt:`--natural-foreign` instead.
Similarly, the ``use_natural_keys`` argument for ``serializers.serialize()`` Similarly, the ``use_natural_keys`` argument for ``serializers.serialize()``
has been deprecated. Use ``use_natural_foreign_keys`` instead. has been deprecated. Use ``use_natural_foreign_keys`` instead.
Merging of ``POST`` and ``GET`` arguments into ``WSGIRequest.REQUEST``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It was already strongly suggested that you use ``GET`` and ``POST`` instead of
``REQUEST``, because the former are more explicit. The property ``REQUEST`` is
deprecated and will be removed in Django 1.9.
``django.utils.datastructures.MergeDict`` class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``MergeDict`` exists primarily to support merging ``POST`` and ``GET``
arguments into a ``REQUEST`` property on ``WSGIRequest``. To merge
dictionaries, use ``dict.update()`` instead. The class ``MergeDict`` is
deprecated and will be removed in Django 1.9.

View File

@ -1,8 +1,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import warnings import warnings
from django.test import SimpleTestCase from django.test import SimpleTestCase, RequestFactory
from django.utils import six from django.utils import six
from django.utils.datastructures import MergeDict
from django.utils.deprecation import RenameMethodsBase from django.utils.deprecation import RenameMethodsBase
@ -156,3 +157,22 @@ class RenameMethodsTests(SimpleTestCase):
'`DeprecatedMixin.old` is deprecated, use `new` instead.', '`DeprecatedMixin.old` is deprecated, use `new` instead.',
'`RenamedMixin.old` is deprecated, use `new` instead.', '`RenamedMixin.old` is deprecated, use `new` instead.',
]) ])
class DeprecatingRequestMergeDictTest(SimpleTestCase):
def test_deprecated_request(self):
"""
Ensure the correct warning is raised when WSGIRequest.REQUEST is
accessed.
"""
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter('always')
request = RequestFactory().get('/')
_ = request.REQUEST
msgs = [str(warning.message) for warning in recorded]
self.assertEqual(msgs, [
'`request.REQUEST` is deprecated, use `request.GET` or '
'`request.POST` instead.',
'`MergeDict` is deprecated, use `dict.update()` instead.',
])

View File

@ -3,6 +3,7 @@ from __future__ import unicode_literals
import copy import copy
import datetime import datetime
import warnings
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
@ -560,6 +561,9 @@ class FormsTestCase(TestCase):
f = SongForm(data) f = SongForm(data)
self.assertEqual(f.errors, {}) self.assertEqual(f.errors, {})
# MergeDict is deprecated, but is supported until removed.
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
data = MergeDict(MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P']))) data = MergeDict(MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P'])))
f = SongForm(data) f = SongForm(data)
self.assertEqual(f.errors, {}) self.assertEqual(f.errors, {})

View File

@ -1,4 +1,5 @@
import json import json
import warnings
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
@ -32,13 +33,20 @@ get_view = login_required(get_view)
def request_data(request, template='base.html', data='sausage'): def request_data(request, template='base.html', data='sausage'):
"A simple view that returns the request data in the context" "A simple view that returns the request data in the context"
# request.REQUEST is deprecated, but needs testing until removed.
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
request_foo = request.REQUEST.get('foo')
request_bar = request.REQUEST.get('bar')
return render_to_response(template, { return render_to_response(template, {
'get-foo':request.GET.get('foo',None), 'get-foo': request.GET.get('foo'),
'get-bar':request.GET.get('bar',None), 'get-bar': request.GET.get('bar'),
'post-foo':request.POST.get('foo',None), 'post-foo': request.POST.get('foo'),
'post-bar':request.POST.get('bar',None), 'post-bar': request.POST.get('bar'),
'request-foo':request.REQUEST.get('foo',None), 'request-foo': request_foo,
'request-bar':request.REQUEST.get('bar',None), 'request-bar': request_bar,
'data': data, 'data': data,
}) })

View File

@ -136,7 +136,7 @@ class SortedDictTests(IgnorePendingDeprecationWarningsMixin, SimpleTestCase):
self.assertEqual(list(reversed(self.d2)), [7, 0, 9, 1]) self.assertEqual(list(reversed(self.d2)), [7, 0, 9, 1])
class MergeDictTests(SimpleTestCase): class MergeDictTests(IgnorePendingDeprecationWarningsMixin, SimpleTestCase):
def test_simple_mergedict(self): def test_simple_mergedict(self):
d1 = {'chris':'cool', 'camri':'cute', 'cotton':'adorable', d1 = {'chris':'cool', 'camri':'cute', 'cotton':'adorable',