mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-08 06:14:47 +03:00
WIP
This commit is contained in:
parent
69fb34b0db
commit
f8854f11f3
|
@ -86,7 +86,7 @@ def clone_request(request, method):
|
|||
ret._full_data = request._full_data
|
||||
ret._content_type = request._content_type
|
||||
ret._stream = request._stream
|
||||
ret.method = method
|
||||
ret._method = method
|
||||
if hasattr(request, '_user'):
|
||||
ret._user = request._user
|
||||
if hasattr(request, '_auth'):
|
||||
|
@ -129,6 +129,11 @@ class Request(object):
|
|||
- authentication_classes(list/tuple). The authentications used to try
|
||||
authenticating the request's user.
|
||||
"""
|
||||
|
||||
_METHOD_PARAM = api_settings.FORM_METHOD_OVERRIDE
|
||||
_CONTENT_PARAM = api_settings.FORM_CONTENT_OVERRIDE
|
||||
_CONTENTTYPE_PARAM = api_settings.FORM_CONTENTTYPE_OVERRIDE
|
||||
|
||||
def __init__(self, request, parsers=None, authenticators=None,
|
||||
negotiator=None, parser_context=None):
|
||||
self._request = request
|
||||
|
@ -139,6 +144,7 @@ class Request(object):
|
|||
self._data = Empty
|
||||
self._files = Empty
|
||||
self._full_data = Empty
|
||||
self._method = Empty
|
||||
self._content_type = Empty
|
||||
self._stream = Empty
|
||||
|
||||
|
@ -156,6 +162,18 @@ class Request(object):
|
|||
def _default_negotiator(self):
|
||||
return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS()
|
||||
|
||||
@property
|
||||
def method(self):
|
||||
"""
|
||||
Returns the HTTP method.
|
||||
|
||||
This allows the `method` to be overridden by using a hidden `form`
|
||||
field on a form POST request.
|
||||
"""
|
||||
if not _hasattr(self, '_method'):
|
||||
self._load_method_and_content_type()
|
||||
return self._method
|
||||
|
||||
@property
|
||||
def content_type(self):
|
||||
meta = self._request.META
|
||||
|
@ -247,6 +265,23 @@ class Request(object):
|
|||
else:
|
||||
self._full_data = self._data
|
||||
|
||||
def _load_method_and_content_type(self):
|
||||
"""
|
||||
Sets the method and content_type, and then check if they've
|
||||
been overridden.
|
||||
"""
|
||||
self._content_type = self.META.get('HTTP_CONTENT_TYPE',
|
||||
self.META.get('CONTENT_TYPE', ''))
|
||||
|
||||
self._perform_form_overloading()
|
||||
|
||||
if not _hasattr(self, '_method'):
|
||||
self._method = self._request.method
|
||||
|
||||
# Allow X-HTTP-METHOD-OVERRIDE header
|
||||
if 'HTTP_X_HTTP_METHOD_OVERRIDE' in self.META:
|
||||
self._method = self.META['HTTP_X_HTTP_METHOD_OVERRIDE'].upper()
|
||||
|
||||
def _load_stream(self):
|
||||
"""
|
||||
Return the content body of the request, as a stream.
|
||||
|
@ -254,7 +289,9 @@ class Request(object):
|
|||
meta = self._request.META
|
||||
try:
|
||||
content_length = int(
|
||||
meta.get('CONTENT_LENGTH', meta.get('HTTP_CONTENT_LENGTH', 0))
|
||||
meta.get(
|
||||
'CONTENT_LENGTH', meta.get('HTTP_CONTENT_LENGTH')
|
||||
)
|
||||
)
|
||||
except (ValueError, TypeError):
|
||||
content_length = 0
|
||||
|
@ -266,6 +303,50 @@ class Request(object):
|
|||
else:
|
||||
self._stream = six.BytesIO(self.raw_post_data)
|
||||
|
||||
def _perform_form_overloading(self):
|
||||
"""
|
||||
If this is a form POST request, then we need to check if the method and
|
||||
content/content_type have been overridden by setting them in hidden
|
||||
form fields or not.
|
||||
"""
|
||||
|
||||
USE_FORM_OVERLOADING = (
|
||||
self._METHOD_PARAM or
|
||||
(self._CONTENT_PARAM and self._CONTENTTYPE_PARAM)
|
||||
)
|
||||
|
||||
# We only need to use form overloading on form POST requests.
|
||||
if (
|
||||
self._request.method != 'POST' or
|
||||
not USE_FORM_OVERLOADING or
|
||||
not is_form_media_type(self._content_type)
|
||||
):
|
||||
return
|
||||
|
||||
# At this point we're committed to parsing the request as form data.
|
||||
self._data = self._request.POST
|
||||
self._files = self._request.FILES
|
||||
self._full_data = self._data.copy()
|
||||
self._full_data.update(self._files)
|
||||
|
||||
# Method overloading - change the method and remove the param from the content.
|
||||
if (
|
||||
self._METHOD_PARAM and
|
||||
self._METHOD_PARAM in self._data
|
||||
):
|
||||
self._method = self._data[self._METHOD_PARAM].upper()
|
||||
|
||||
# Content overloading - modify the content type, and force re-parse.
|
||||
if (
|
||||
self._CONTENT_PARAM and
|
||||
self._CONTENTTYPE_PARAM and
|
||||
self._CONTENT_PARAM in self._data and
|
||||
self._CONTENTTYPE_PARAM in self._data
|
||||
):
|
||||
self._content_type = self._data[self._CONTENTTYPE_PARAM]
|
||||
self._stream = six.BytesIO(self._data[self._CONTENT_PARAM].encode(self.parser_context['encoding']))
|
||||
self._data, self._files, self._full_data = (Empty, Empty, Empty)
|
||||
|
||||
def _parse(self):
|
||||
"""
|
||||
Parse the request content, returning a two-tuple of (data, files)
|
||||
|
|
|
@ -92,6 +92,9 @@ DEFAULTS = {
|
|||
'rest_framework.renderers.JSONRenderer'
|
||||
),
|
||||
'TEST_REQUEST_DEFAULT_FORMAT': 'multipart',
|
||||
'FORM_METHOD_OVERRIDE': '_method',
|
||||
'FORM_CONTENT_OVERRIDE': '_content',
|
||||
'FORM_CONTENTTYPE_OVERRIDE': '_content_type',
|
||||
|
||||
# Hyperlink settings
|
||||
'URL_FORMAT_OVERRIDE': 'format',
|
||||
|
|
Loading…
Reference in New Issue
Block a user