Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #18659 -- Deprecated request.REQUEST and MergeDict

Thanks Aymeric Augustin for the suggestion.
  • Loading branch information...
commit 2fb5a51fa3ac276efc7121ec9de91f092a986104 1 parent 98788d3
Bouke Haarsma authored October 15, 2013 timgraham committed October 17, 2013
12  django/contrib/admin/options.py
@@ -1284,8 +1284,10 @@ def add_view(self, request, form_url='', extra_context=None):
1284 1284
         context = dict(self.admin_site.each_context(),
1285 1285
             title=_('Add %s') % force_text(opts.verbose_name),
1286 1286
             adminform=adminForm,
1287  
-            is_popup=IS_POPUP_VAR in request.REQUEST,
1288  
-            to_field=request.REQUEST.get(TO_FIELD_VAR),
  1287
+            is_popup=(IS_POPUP_VAR in request.POST or
  1288
+                      IS_POPUP_VAR in request.GET),
  1289
+            to_field=request.POST.get(TO_FIELD_VAR,
  1290
+                                      request.GET.get(TO_FIELD_VAR)),
1289 1291
             media=media,
1290 1292
             inline_admin_formsets=inline_admin_formsets,
1291 1293
             errors=helpers.AdminErrorList(form, formsets),
@@ -1357,8 +1359,10 @@ def change_view(self, request, object_id, form_url='', extra_context=None):
1357 1359
             adminform=adminForm,
1358 1360
             object_id=object_id,
1359 1361
             original=obj,
1360  
-            is_popup=IS_POPUP_VAR in request.REQUEST,
1361  
-            to_field=request.REQUEST.get(TO_FIELD_VAR),
  1362
+            is_popup=(IS_POPUP_VAR in request.POST or
  1363
+                      IS_POPUP_VAR in request.GET),
  1364
+            to_field=request.POST.get(TO_FIELD_VAR,
  1365
+                                      request.GET.get(TO_FIELD_VAR)),
1362 1366
             media=media,
1363 1367
             inline_admin_formsets=inline_admin_formsets,
1364 1368
             errors=helpers.AdminErrorList(form, formsets),
3  django/contrib/auth/admin.py
@@ -144,7 +144,8 @@ def user_change_password(self, request, id, form_url=''):
144 144
             'adminForm': adminForm,
145 145
             'form_url': form_url,
146 146
             'form': form,
147  
-            'is_popup': IS_POPUP_VAR in request.REQUEST,
  147
+            'is_popup': (IS_POPUP_VAR in request.POST or
  148
+                         IS_POPUP_VAR in request.GET),
148 149
             'add': True,
149 150
             'change': False,
150 151
             'has_delete_permission': False,
1  django/contrib/auth/tests/test_views.py
@@ -526,7 +526,6 @@ def test_login_csrf_rotate(self, password='password'):
526 526
         req.COOKIES[settings.CSRF_COOKIE_NAME] = token1
527 527
         req.method = "POST"
528 528
         req.POST = {'username': 'testclient', 'password': password, 'csrfmiddlewaretoken': token1}
529  
-        req.REQUEST = req.POST
530 529
 
531 530
         # Use POST request to log in
532 531
         SessionMiddleware().process_request(req)
9  django/contrib/auth/views.py
@@ -28,7 +28,8 @@ def login(request, template_name='registration/login.html',
28 28
     """
29 29
     Displays the login form and handles the login action.
30 30
     """
31  
-    redirect_to = request.REQUEST.get(redirect_field_name, '')
  31
+    redirect_to = request.POST.get(redirect_field_name,
  32
+                                   request.GET.get(redirect_field_name, ''))
32 33
 
33 34
     if request.method == "POST":
34 35
         form = authentication_form(request, data=request.POST)
@@ -71,8 +72,10 @@ def logout(request, next_page=None,
71 72
     if next_page is not None:
72 73
         next_page = resolve_url(next_page)
73 74
 
74  
-    if redirect_field_name in request.REQUEST:
75  
-        next_page = request.REQUEST[redirect_field_name]
  75
+    if (redirect_field_name in request.POST or
  76
+            redirect_field_name in request.GET):
  77
+        next_page = request.POST.get(redirect_field_name,
  78
+                                     request.GET.get(redirect_field_name))
76 79
         # Security check -- don't allow redirection to a different host.
77 80
         if not is_safe_url(url=next_page, host=request.get_host()):
78 81
             next_page = request.path
3  django/core/handlers/wsgi.py
@@ -5,6 +5,7 @@
5 5
 import sys
6 6
 from io import BytesIO
7 7
 from threading import Lock
  8
+import warnings
8 9
 
9 10
 from django import http
10 11
 from django.conf import settings
@@ -129,6 +130,8 @@ def _parse_content_type(self, ctype):
129 130
         return content_type, content_params
130 131
 
131 132
     def _get_request(self):
  133
+        warnings.warn('`request.REQUEST` is deprecated, use `request.GET` or '
  134
+                      '`request.POST` instead.', PendingDeprecationWarning, 2)
132 135
         if not hasattr(self, '_request'):
133 136
             self._request = datastructures.MergeDict(self.POST, self.GET)
134 137
         return self._request
2  django/utils/datastructures.py
@@ -12,6 +12,8 @@ class MergeDict(object):
12 12
     first occurrence will be used.
13 13
     """
14 14
     def __init__(self, *dicts):
  15
+        warnings.warn('`MergeDict` is deprecated, use `dict.update()` '
  16
+                      'instead.', PendingDeprecationWarning, 2)
15 17
         self.dicts = dicts
16 18
 
17 19
     def __bool__(self):
2  django/views/i18n.py
@@ -24,7 +24,7 @@ def set_language(request):
24 24
     redirect to the page in the request (the 'next' parameter) without changing
25 25
     any state.
26 26
     """
27  
-    next = request.REQUEST.get('next')
  27
+    next = request.POST.get('next', request.GET.get('next'))
28 28
     if not is_safe_url(url=next, host=request.get_host()):
29 29
         next = request.META.get('HTTP_REFERER')
30 30
         if not is_safe_url(url=next, host=request.get_host()):
4  docs/internals/deprecation.txt
@@ -469,6 +469,10 @@ these changes.
469 469
 
470 470
 * ``django.forms.get_declared_fields`` will be removed.
471 471
 
  472
+* The ``WSGIRequest.REQUEST`` property will be removed.
  473
+
  474
+* The class ``django.utils.datastructures.MergeDict`` will be removed.
  475
+
472 476
 2.0
473 477
 ---
474 478
 
3  docs/ref/request-response.txt
@@ -110,6 +110,9 @@ All attributes should be considered read-only, unless stated otherwise below.
110 110
 
111 111
 .. attribute:: HttpRequest.REQUEST
112 112
 
  113
+    .. deprecated:: 1.7
  114
+        Use the more explicit ``GET`` and ``POST`` instead.
  115
+
113 116
     For convenience, a dictionary-like object that searches ``POST`` first,
114 117
     then ``GET``. Inspired by PHP's ``$_REQUEST``.
115 118
 
15  docs/releases/1.7.txt
@@ -639,3 +639,18 @@ deprecated. Use :djadminopt:`--natural-foreign` instead.
639 639
 
640 640
 Similarly, the ``use_natural_keys`` argument for ``serializers.serialize()``
641 641
 has been deprecated. Use ``use_natural_foreign_keys`` instead.
  642
+
  643
+Merging of ``POST`` and ``GET`` arguments into ``WSGIRequest.REQUEST``
  644
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  645
+
  646
+It was already strongly suggested that you use ``GET`` and ``POST`` instead of
  647
+``REQUEST``, because the former are more explicit. The property ``REQUEST`` is
  648
+deprecated and will be removed in Django 1.9.
  649
+
  650
+``django.utils.datastructures.MergeDict`` class
  651
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  652
+
  653
+``MergeDict`` exists primarily to support merging ``POST`` and ``GET``
  654
+arguments into a ``REQUEST`` property on ``WSGIRequest``. To merge
  655
+dictionaries, use ``dict.update()`` instead. The class ``MergeDict`` is
  656
+deprecated and will be removed in Django 1.9.
22  tests/deprecation/tests.py
... ...
@@ -1,8 +1,9 @@
1 1
 from __future__ import unicode_literals
2 2
 import warnings
3 3
 
4  
-from django.test import SimpleTestCase
  4
+from django.test import SimpleTestCase, RequestFactory
5 5
 from django.utils import six
  6
+from django.utils.datastructures import MergeDict
6 7
 from django.utils.deprecation import RenameMethodsBase
7 8
 
8 9
 
@@ -156,3 +157,22 @@ class Deprecated(DeprecatedMixin, RenamedMixin, Renamed):
156 157
                 '`DeprecatedMixin.old` is deprecated, use `new` instead.',
157 158
                 '`RenamedMixin.old` is deprecated, use `new` instead.',
158 159
             ])
  160
+
  161
+
  162
+class DeprecatingRequestMergeDictTest(SimpleTestCase):
  163
+    def test_deprecated_request(self):
  164
+        """
  165
+        Ensure the correct warning is raised when WSGIRequest.REQUEST is
  166
+        accessed.
  167
+        """
  168
+        with warnings.catch_warnings(record=True) as recorded:
  169
+            warnings.simplefilter('always')
  170
+            request = RequestFactory().get('/')
  171
+            _ = request.REQUEST
  172
+
  173
+            msgs = [str(warning.message) for warning in recorded]
  174
+            self.assertEqual(msgs, [
  175
+                '`request.REQUEST` is deprecated, use `request.GET` or '
  176
+                '`request.POST` instead.',
  177
+                '`MergeDict` is deprecated, use `dict.update()` instead.',
  178
+            ])
10  tests/forms_tests/tests/test_forms.py
@@ -3,6 +3,7 @@
3 3
 
4 4
 import copy
5 5
 import datetime
  6
+import warnings
6 7
 
7 8
 from django.core.files.uploadedfile import SimpleUploadedFile
8 9
 from django.core.validators import RegexValidator
@@ -560,9 +561,12 @@ class SongForm(Form):
560 561
         f = SongForm(data)
561 562
         self.assertEqual(f.errors, {})
562 563
 
563  
-        data = MergeDict(MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P'])))
564  
-        f = SongForm(data)
565  
-        self.assertEqual(f.errors, {})
  564
+        # MergeDict is deprecated, but is supported until removed.
  565
+        with warnings.catch_warnings(record=True):
  566
+            warnings.simplefilter("always")
  567
+            data = MergeDict(MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P'])))
  568
+            f = SongForm(data)
  569
+            self.assertEqual(f.errors, {})
566 570
 
567 571
     def test_multiple_hidden(self):
568 572
         class SongForm(Form):
20  tests/test_client_regress/views.py
... ...
@@ -1,4 +1,5 @@
1 1
 import json
  2
+import warnings
2 3
 
3 4
 from django.conf import settings
4 5
 from django.contrib.auth.decorators import login_required
@@ -32,13 +33,20 @@ def get_view(request):
32 33
 
33 34
 def request_data(request, template='base.html', data='sausage'):
34 35
     "A simple view that returns the request data in the context"
  36
+
  37
+    # request.REQUEST is deprecated, but needs testing until removed.
  38
+    with warnings.catch_warnings(record=True) as w:
  39
+        warnings.simplefilter("always")
  40
+        request_foo = request.REQUEST.get('foo')
  41
+        request_bar = request.REQUEST.get('bar')
  42
+
35 43
     return render_to_response(template, {
36  
-        'get-foo':request.GET.get('foo',None),
37  
-        'get-bar':request.GET.get('bar',None),
38  
-        'post-foo':request.POST.get('foo',None),
39  
-        'post-bar':request.POST.get('bar',None),
40  
-        'request-foo':request.REQUEST.get('foo',None),
41  
-        'request-bar':request.REQUEST.get('bar',None),
  44
+        'get-foo': request.GET.get('foo'),
  45
+        'get-bar': request.GET.get('bar'),
  46
+        'post-foo': request.POST.get('foo'),
  47
+        'post-bar': request.POST.get('bar'),
  48
+        'request-foo': request_foo,
  49
+        'request-bar': request_bar,
42 50
         'data': data,
43 51
     })
44 52
 
2  tests/utils_tests/test_datastructures.py
@@ -136,7 +136,7 @@ def test_reversed(self):
136 136
         self.assertEqual(list(reversed(self.d2)), [7, 0, 9, 1])
137 137
 
138 138
 
139  
-class MergeDictTests(SimpleTestCase):
  139
+class MergeDictTests(IgnorePendingDeprecationWarningsMixin, SimpleTestCase):
140 140
 
141 141
     def test_simple_mergedict(self):
142 142
         d1 = {'chris':'cool', 'camri':'cute', 'cotton':'adorable',

0 notes on commit 2fb5a51

Please sign in to comment.
Something went wrong with that request. Please try again.