2012-09-20 16:06:27 +04:00
|
|
|
"""
|
2013-04-25 15:47:34 +04:00
|
|
|
The Request class is used as a wrapper around the standard request object.
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
The wrapped request then offers a richer API, in particular :
|
|
|
|
|
|
|
|
- content automatically parsed according to `Content-Type` header,
|
2014-09-26 13:46:52 +04:00
|
|
|
and available as `request.data`
|
2012-09-20 16:06:27 +04:00
|
|
|
- full support of PUT method, including support for file uploads
|
|
|
|
- form overloading of HTTP method, content type and content
|
|
|
|
"""
|
2018-09-09 13:53:41 +03:00
|
|
|
import io
|
2017-11-23 10:58:04 +03:00
|
|
|
import sys
|
|
|
|
from contextlib import contextmanager
|
|
|
|
|
2013-02-05 01:16:34 +04:00
|
|
|
from django.conf import settings
|
2017-11-23 10:57:31 +03:00
|
|
|
from django.http import HttpRequest, QueryDict
|
2016-09-21 13:49:09 +03:00
|
|
|
from django.http.request import RawPostDataException
|
2013-02-14 17:02:28 +04:00
|
|
|
from django.utils.datastructures import MultiValueDict
|
2024-04-26 17:50:27 +03:00
|
|
|
from django.utils.http import parse_header_parameters
|
2015-06-18 16:38:29 +03:00
|
|
|
|
2022-07-14 15:20:36 +03:00
|
|
|
from rest_framework import exceptions
|
2012-09-20 16:06:27 +04:00
|
|
|
from rest_framework.settings import api_settings
|
2012-10-15 16:27:50 +04:00
|
|
|
|
|
|
|
|
|
|
|
def is_form_media_type(media_type):
|
|
|
|
"""
|
|
|
|
Return True if the media type is a valid form media type.
|
|
|
|
"""
|
2022-07-14 15:20:36 +03:00
|
|
|
base_media_type, params = parse_header_parameters(media_type)
|
2012-10-27 13:32:49 +04:00
|
|
|
return (base_media_type == 'application/x-www-form-urlencoded' or
|
|
|
|
base_media_type == 'multipart/form-data')
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
|
2019-04-30 18:53:44 +03:00
|
|
|
class override_method:
|
2013-08-29 15:55:56 +04:00
|
|
|
"""
|
|
|
|
A context manager that temporarily overrides the method on a request,
|
|
|
|
additionally setting the `view.request` attribute.
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
|
|
|
with override_method(view, request, 'POST') as request:
|
|
|
|
... # Do stuff with `view` and `request`
|
|
|
|
"""
|
2016-03-17 14:06:47 +03:00
|
|
|
|
2013-08-29 15:55:56 +04:00
|
|
|
def __init__(self, view, request, method):
|
|
|
|
self.view = view
|
|
|
|
self.request = request
|
|
|
|
self.method = method
|
2014-08-17 02:05:46 +04:00
|
|
|
self.action = getattr(view, 'action', None)
|
2013-08-29 15:55:56 +04:00
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
self.view.request = clone_request(self.request, self.method)
|
2015-05-14 05:53:32 +03:00
|
|
|
# For viewsets we also set the `.action` attribute.
|
|
|
|
action_map = getattr(self.view, 'action_map', {})
|
|
|
|
self.view.action = action_map.get(self.method.lower())
|
2013-08-29 15:55:56 +04:00
|
|
|
return self.view.request
|
|
|
|
|
|
|
|
def __exit__(self, *args, **kwarg):
|
|
|
|
self.view.request = self.request
|
2015-05-14 05:53:32 +03:00
|
|
|
self.view.action = self.action
|
2013-08-29 15:55:56 +04:00
|
|
|
|
|
|
|
|
2017-11-23 10:58:04 +03:00
|
|
|
class WrappedAttributeError(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
@contextmanager
|
|
|
|
def wrap_attributeerrors():
|
|
|
|
"""
|
|
|
|
Used to re-raise AttributeErrors caught during authentication, preventing
|
|
|
|
these errors from otherwise being handled by the attribute access protocol.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
yield
|
|
|
|
except AttributeError:
|
|
|
|
info = sys.exc_info()
|
|
|
|
exc = WrappedAttributeError(str(info[1]))
|
2019-04-30 18:53:44 +03:00
|
|
|
raise exc.with_traceback(info[2])
|
2017-11-23 10:58:04 +03:00
|
|
|
|
|
|
|
|
2019-04-30 18:53:44 +03:00
|
|
|
class Empty:
|
2012-09-20 16:06:27 +04:00
|
|
|
"""
|
|
|
|
Placeholder for unset attributes.
|
|
|
|
Cannot use `None`, as that may be a valid value.
|
|
|
|
"""
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def _hasattr(obj, name):
|
|
|
|
return not getattr(obj, name) is Empty
|
|
|
|
|
|
|
|
|
2012-09-28 14:53:51 +04:00
|
|
|
def clone_request(request, method):
|
|
|
|
"""
|
|
|
|
Internal helper method to clone a request, replacing with a different
|
|
|
|
HTTP method. Used for checking permissions against other methods.
|
|
|
|
"""
|
2015-01-27 09:56:57 +03:00
|
|
|
ret = Request(request=request._request,
|
2013-02-14 16:50:55 +04:00
|
|
|
parsers=request.parsers,
|
|
|
|
authenticators=request.authenticators,
|
|
|
|
negotiator=request.negotiator,
|
|
|
|
parser_context=request.parser_context)
|
2012-09-28 14:53:51 +04:00
|
|
|
ret._data = request._data
|
|
|
|
ret._files = request._files
|
2014-09-26 13:46:52 +04:00
|
|
|
ret._full_data = request._full_data
|
2012-09-28 14:53:51 +04:00
|
|
|
ret._content_type = request._content_type
|
|
|
|
ret._stream = request._stream
|
2015-09-17 18:34:03 +03:00
|
|
|
ret.method = method
|
2012-10-09 15:48:49 +04:00
|
|
|
if hasattr(request, '_user'):
|
|
|
|
ret._user = request._user
|
|
|
|
if hasattr(request, '_auth'):
|
|
|
|
ret._auth = request._auth
|
2013-02-14 16:50:55 +04:00
|
|
|
if hasattr(request, '_authenticator'):
|
|
|
|
ret._authenticator = request._authenticator
|
2014-11-05 14:08:32 +03:00
|
|
|
if hasattr(request, 'accepted_renderer'):
|
|
|
|
ret.accepted_renderer = request.accepted_renderer
|
|
|
|
if hasattr(request, 'accepted_media_type'):
|
|
|
|
ret.accepted_media_type = request.accepted_media_type
|
2015-01-27 09:56:57 +03:00
|
|
|
if hasattr(request, 'version'):
|
|
|
|
ret.version = request.version
|
2015-01-28 04:10:17 +03:00
|
|
|
if hasattr(request, 'versioning_scheme'):
|
|
|
|
ret.versioning_scheme = request.versioning_scheme
|
2012-09-28 14:53:51 +04:00
|
|
|
return ret
|
|
|
|
|
|
|
|
|
2019-04-30 18:53:44 +03:00
|
|
|
class ForcedAuthentication:
|
2013-06-30 00:02:58 +04:00
|
|
|
"""
|
|
|
|
This authentication class is used if the test client or request factory
|
|
|
|
forcibly authenticated the request.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, force_user, force_token):
|
|
|
|
self.force_user = force_user
|
|
|
|
self.force_token = force_token
|
|
|
|
|
|
|
|
def authenticate(self, request):
|
|
|
|
return (self.force_user, self.force_token)
|
|
|
|
|
|
|
|
|
2019-04-30 18:53:44 +03:00
|
|
|
class Request:
|
2012-09-20 16:06:27 +04:00
|
|
|
"""
|
|
|
|
Wrapper allowing to enhance a standard `HttpRequest` instance.
|
|
|
|
|
|
|
|
Kwargs:
|
|
|
|
- request(HttpRequest). The original request instance.
|
2020-08-06 02:51:06 +03:00
|
|
|
- parsers(list/tuple). The parsers to use for parsing the
|
2012-09-20 16:06:27 +04:00
|
|
|
request content.
|
2020-08-06 02:51:06 +03:00
|
|
|
- authenticators(list/tuple). The authenticators used to try
|
2012-09-20 16:06:27 +04:00
|
|
|
authenticating the request's user.
|
|
|
|
"""
|
2016-03-17 14:06:47 +03:00
|
|
|
|
2012-10-05 17:48:33 +04:00
|
|
|
def __init__(self, request, parsers=None, authenticators=None,
|
2012-10-15 16:27:50 +04:00
|
|
|
negotiator=None, parser_context=None):
|
2017-11-23 10:57:31 +03:00
|
|
|
assert isinstance(request, HttpRequest), (
|
|
|
|
'The `request` argument must be an instance of '
|
|
|
|
'`django.http.HttpRequest`, not `{}.{}`.'
|
|
|
|
.format(request.__class__.__module__, request.__class__.__name__)
|
|
|
|
)
|
|
|
|
|
2012-09-20 16:06:27 +04:00
|
|
|
self._request = request
|
2012-10-05 17:48:33 +04:00
|
|
|
self.parsers = parsers or ()
|
|
|
|
self.authenticators = authenticators or ()
|
|
|
|
self.negotiator = negotiator or self._default_negotiator()
|
2012-10-15 16:27:50 +04:00
|
|
|
self.parser_context = parser_context
|
2012-09-20 16:06:27 +04:00
|
|
|
self._data = Empty
|
|
|
|
self._files = Empty
|
2014-09-26 13:46:52 +04:00
|
|
|
self._full_data = Empty
|
2012-09-20 16:06:27 +04:00
|
|
|
self._content_type = Empty
|
|
|
|
self._stream = Empty
|
|
|
|
|
2012-10-15 16:27:50 +04:00
|
|
|
if self.parser_context is None:
|
2012-10-18 01:19:59 +04:00
|
|
|
self.parser_context = {}
|
|
|
|
self.parser_context['request'] = self
|
2013-02-05 01:16:34 +04:00
|
|
|
self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET
|
2012-10-15 16:27:50 +04:00
|
|
|
|
2013-06-30 00:02:58 +04:00
|
|
|
force_user = getattr(request, '_force_auth_user', None)
|
|
|
|
force_token = getattr(request, '_force_auth_token', None)
|
2017-01-08 19:09:23 +03:00
|
|
|
if force_user is not None or force_token is not None:
|
2013-06-30 00:02:58 +04:00
|
|
|
forced_auth = ForcedAuthentication(force_user, force_token)
|
|
|
|
self.authenticators = (forced_auth,)
|
|
|
|
|
2020-03-29 14:01:14 +03:00
|
|
|
def __repr__(self):
|
|
|
|
return '<%s.%s: %s %r>' % (
|
|
|
|
self.__class__.__module__,
|
|
|
|
self.__class__.__name__,
|
|
|
|
self.method,
|
|
|
|
self.get_full_path())
|
|
|
|
|
2023-02-22 18:39:01 +03:00
|
|
|
# Allow generic typing checking for requests.
|
|
|
|
def __class_getitem__(cls, *args, **kwargs):
|
|
|
|
return cls
|
|
|
|
|
2012-10-05 17:48:33 +04:00
|
|
|
def _default_negotiator(self):
|
2012-10-18 02:09:11 +04:00
|
|
|
return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS()
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
@property
|
|
|
|
def content_type(self):
|
2015-09-17 17:17:29 +03:00
|
|
|
meta = self._request.META
|
|
|
|
return meta.get('CONTENT_TYPE', meta.get('HTTP_CONTENT_TYPE', ''))
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
@property
|
|
|
|
def stream(self):
|
|
|
|
"""
|
|
|
|
Returns an object that may be used to stream the request content.
|
|
|
|
"""
|
|
|
|
if not _hasattr(self, '_stream'):
|
|
|
|
self._load_stream()
|
|
|
|
return self._stream
|
|
|
|
|
2012-09-26 15:39:39 +04:00
|
|
|
@property
|
2014-09-26 13:46:52 +04:00
|
|
|
def query_params(self):
|
2012-09-26 15:39:39 +04:00
|
|
|
"""
|
|
|
|
More semantically correct name for request.GET.
|
|
|
|
"""
|
|
|
|
return self._request.GET
|
|
|
|
|
2014-09-26 13:46:52 +04:00
|
|
|
@property
|
|
|
|
def data(self):
|
|
|
|
if not _hasattr(self, '_full_data'):
|
2024-07-17 19:51:39 +03:00
|
|
|
with wrap_attributeerrors():
|
|
|
|
self._load_data_and_files()
|
2014-09-26 13:46:52 +04:00
|
|
|
return self._full_data
|
|
|
|
|
2012-09-20 16:06:27 +04:00
|
|
|
@property
|
|
|
|
def user(self):
|
|
|
|
"""
|
|
|
|
Returns the user associated with the current request, as authenticated
|
|
|
|
by the authentication classes provided to the request.
|
|
|
|
"""
|
|
|
|
if not hasattr(self, '_user'):
|
2017-11-23 10:58:04 +03:00
|
|
|
with wrap_attributeerrors():
|
|
|
|
self._authenticate()
|
2012-09-20 16:06:27 +04:00
|
|
|
return self._user
|
|
|
|
|
2012-11-24 21:18:32 +04:00
|
|
|
@user.setter
|
|
|
|
def user(self, value):
|
2013-02-11 00:08:36 +04:00
|
|
|
"""
|
|
|
|
Sets the user on the current request. This is necessary to maintain
|
2014-01-09 19:39:37 +04:00
|
|
|
compatibility with django.contrib.auth where the user property is
|
2013-02-11 00:08:36 +04:00
|
|
|
set in the login and logout functions.
|
2014-11-28 23:12:13 +03:00
|
|
|
|
2014-12-17 16:22:52 +03:00
|
|
|
Note that we also set the user on Django's underlying `HttpRequest`
|
|
|
|
instance, ensuring that it is available to any middleware in the stack.
|
2013-02-11 00:08:36 +04:00
|
|
|
"""
|
|
|
|
self._user = value
|
2014-11-28 23:12:13 +03:00
|
|
|
self._request.user = value
|
2012-11-24 21:18:32 +04:00
|
|
|
|
2012-09-20 16:06:27 +04:00
|
|
|
@property
|
|
|
|
def auth(self):
|
|
|
|
"""
|
|
|
|
Returns any non-user authentication information associated with the
|
|
|
|
request, such as an authentication token.
|
|
|
|
"""
|
|
|
|
if not hasattr(self, '_auth'):
|
2017-11-23 10:58:04 +03:00
|
|
|
with wrap_attributeerrors():
|
|
|
|
self._authenticate()
|
2012-09-20 16:06:27 +04:00
|
|
|
return self._auth
|
|
|
|
|
2012-12-21 03:48:10 +04:00
|
|
|
@auth.setter
|
|
|
|
def auth(self, value):
|
|
|
|
"""
|
|
|
|
Sets any non-user authentication information associated with the
|
|
|
|
request, such as an authentication token.
|
|
|
|
"""
|
|
|
|
self._auth = value
|
2014-12-17 16:22:52 +03:00
|
|
|
self._request.auth = value
|
2012-12-21 03:48:10 +04:00
|
|
|
|
2012-11-13 15:27:09 +04:00
|
|
|
@property
|
|
|
|
def successful_authenticator(self):
|
|
|
|
"""
|
|
|
|
Return the instance of the authentication instance class that was used
|
|
|
|
to authenticate the request, or `None`.
|
|
|
|
"""
|
2013-02-11 00:08:36 +04:00
|
|
|
if not hasattr(self, '_authenticator'):
|
2017-11-23 10:58:04 +03:00
|
|
|
with wrap_attributeerrors():
|
|
|
|
self._authenticate()
|
2012-11-13 15:27:09 +04:00
|
|
|
return self._authenticator
|
|
|
|
|
2012-09-20 16:06:27 +04:00
|
|
|
def _load_data_and_files(self):
|
|
|
|
"""
|
2014-11-25 14:42:43 +03:00
|
|
|
Parses the request content into `self.data`.
|
2012-09-20 16:06:27 +04:00
|
|
|
"""
|
|
|
|
if not _hasattr(self, '_data'):
|
|
|
|
self._data, self._files = self._parse()
|
2014-09-26 13:46:52 +04:00
|
|
|
if self._files:
|
2015-03-05 15:34:42 +03:00
|
|
|
self._full_data = self._data.copy()
|
|
|
|
self._full_data.update(self._files)
|
2014-09-26 13:46:52 +04:00
|
|
|
else:
|
|
|
|
self._full_data = self._data
|
2012-09-20 16:06:27 +04:00
|
|
|
|
2018-02-05 18:24:13 +03:00
|
|
|
# if a form media type, copy data & files refs to the underlying
|
|
|
|
# http request so that closable objects are handled appropriately.
|
|
|
|
if is_form_media_type(self.content_type):
|
|
|
|
self._request._post = self.POST
|
|
|
|
self._request._files = self.FILES
|
2017-07-10 15:42:02 +03:00
|
|
|
|
2012-09-20 16:06:27 +04:00
|
|
|
def _load_stream(self):
|
|
|
|
"""
|
|
|
|
Return the content body of the request, as a stream.
|
|
|
|
"""
|
2015-09-17 17:17:29 +03:00
|
|
|
meta = self._request.META
|
2012-09-20 16:06:27 +04:00
|
|
|
try:
|
2014-08-19 16:28:07 +04:00
|
|
|
content_length = int(
|
2015-09-17 17:17:29 +03:00
|
|
|
meta.get('CONTENT_LENGTH', meta.get('HTTP_CONTENT_LENGTH', 0))
|
2014-08-19 16:28:07 +04:00
|
|
|
)
|
2012-09-20 16:06:27 +04:00
|
|
|
except (ValueError, TypeError):
|
|
|
|
content_length = 0
|
|
|
|
|
|
|
|
if content_length == 0:
|
|
|
|
self._stream = None
|
2016-09-21 13:49:09 +03:00
|
|
|
elif not self._request._read_started:
|
2012-09-20 16:06:27 +04:00
|
|
|
self._stream = self._request
|
|
|
|
else:
|
2018-09-09 13:53:41 +03:00
|
|
|
self._stream = io.BytesIO(self.body)
|
2016-09-21 13:49:09 +03:00
|
|
|
|
|
|
|
def _supports_form_parsing(self):
|
|
|
|
"""
|
|
|
|
Return True if this requests supports parsing form data.
|
|
|
|
"""
|
|
|
|
form_media = (
|
|
|
|
'application/x-www-form-urlencoded',
|
|
|
|
'multipart/form-data'
|
|
|
|
)
|
2021-03-26 15:27:10 +03:00
|
|
|
return any(parser.media_type in form_media for parser in self.parsers)
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
def _parse(self):
|
|
|
|
"""
|
|
|
|
Parse the request content, returning a two-tuple of (data, files)
|
|
|
|
|
|
|
|
May raise an `UnsupportedMediaType`, or `ParseError` exception.
|
|
|
|
"""
|
2012-10-18 01:39:07 +04:00
|
|
|
media_type = self.content_type
|
2016-09-21 13:49:09 +03:00
|
|
|
try:
|
|
|
|
stream = self.stream
|
|
|
|
except RawPostDataException:
|
|
|
|
if not hasattr(self._request, '_post'):
|
|
|
|
raise
|
|
|
|
# If request.POST has been accessed in middleware, and a method='POST'
|
|
|
|
# request was made with 'multipart/form-data', then the request stream
|
|
|
|
# will already have been exhausted.
|
|
|
|
if self._supports_form_parsing():
|
|
|
|
return (self._request.POST, self._request.FILES)
|
|
|
|
stream = None
|
2012-10-18 01:39:07 +04:00
|
|
|
|
|
|
|
if stream is None or media_type is None:
|
2017-08-31 04:36:05 +03:00
|
|
|
if media_type and is_form_media_type(media_type):
|
2016-10-12 17:46:24 +03:00
|
|
|
empty_data = QueryDict('', encoding=self._request._encoding)
|
|
|
|
else:
|
|
|
|
empty_data = {}
|
2013-02-14 17:02:28 +04:00
|
|
|
empty_files = MultiValueDict()
|
|
|
|
return (empty_data, empty_files)
|
2012-09-20 16:06:27 +04:00
|
|
|
|
2012-10-18 01:58:18 +04:00
|
|
|
parser = self.negotiator.select_parser(self, self.parsers)
|
2012-10-05 17:48:33 +04:00
|
|
|
|
|
|
|
if not parser:
|
2012-10-18 01:39:07 +04:00
|
|
|
raise exceptions.UnsupportedMediaType(media_type)
|
|
|
|
|
2013-12-03 12:58:05 +04:00
|
|
|
try:
|
|
|
|
parsed = parser.parse(stream, media_type, self.parser_context)
|
2017-11-23 10:58:04 +03:00
|
|
|
except Exception:
|
2013-12-03 12:58:05 +04:00
|
|
|
# If we get an exception during parsing, fill in empty data and
|
|
|
|
# re-raise. Ensures we don't simply repeat the error when
|
|
|
|
# attempting to render the browsable renderer response, or when
|
2013-12-09 11:34:08 +04:00
|
|
|
# logging the request or similar.
|
2014-03-22 13:22:08 +04:00
|
|
|
self._data = QueryDict('', encoding=self._request._encoding)
|
2013-12-03 12:58:05 +04:00
|
|
|
self._files = MultiValueDict()
|
2014-09-26 13:46:52 +04:00
|
|
|
self._full_data = self._data
|
2013-12-03 12:58:05 +04:00
|
|
|
raise
|
2012-09-20 16:06:27 +04:00
|
|
|
|
2012-10-05 17:48:33 +04:00
|
|
|
# Parser classes may return the raw data, or a
|
|
|
|
# DataAndFiles object. Unpack the result as required.
|
|
|
|
try:
|
|
|
|
return (parsed.data, parsed.files)
|
|
|
|
except AttributeError:
|
2013-02-14 17:02:28 +04:00
|
|
|
empty_files = MultiValueDict()
|
|
|
|
return (parsed, empty_files)
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
def _authenticate(self):
|
|
|
|
"""
|
2012-11-13 15:27:09 +04:00
|
|
|
Attempt to authenticate the request using each authentication instance
|
|
|
|
in turn.
|
2012-09-20 16:06:27 +04:00
|
|
|
"""
|
2012-10-05 17:48:33 +04:00
|
|
|
for authenticator in self.authenticators:
|
2013-06-03 15:32:57 +04:00
|
|
|
try:
|
|
|
|
user_auth_tuple = authenticator.authenticate(self)
|
|
|
|
except exceptions.APIException:
|
|
|
|
self._not_authenticated()
|
|
|
|
raise
|
|
|
|
|
2014-08-19 16:54:52 +04:00
|
|
|
if user_auth_tuple is not None:
|
2013-06-03 15:32:57 +04:00
|
|
|
self._authenticator = authenticator
|
2014-12-17 16:22:52 +03:00
|
|
|
self.user, self.auth = user_auth_tuple
|
2013-06-03 15:32:57 +04:00
|
|
|
return
|
|
|
|
|
|
|
|
self._not_authenticated()
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
def _not_authenticated(self):
|
|
|
|
"""
|
2017-02-20 12:33:54 +03:00
|
|
|
Set authenticator, user & authtoken representing an unauthenticated request.
|
2012-09-20 16:06:27 +04:00
|
|
|
|
2017-02-20 12:33:54 +03:00
|
|
|
Defaults are None, AnonymousUser & None.
|
2012-09-20 16:06:27 +04:00
|
|
|
"""
|
2013-06-03 15:32:57 +04:00
|
|
|
self._authenticator = None
|
|
|
|
|
2012-09-20 16:06:27 +04:00
|
|
|
if api_settings.UNAUTHENTICATED_USER:
|
2014-11-28 23:12:13 +03:00
|
|
|
self.user = api_settings.UNAUTHENTICATED_USER()
|
2012-09-20 16:06:27 +04:00
|
|
|
else:
|
2014-11-28 23:12:13 +03:00
|
|
|
self.user = None
|
2012-09-20 16:06:27 +04:00
|
|
|
|
|
|
|
if api_settings.UNAUTHENTICATED_TOKEN:
|
2014-12-17 16:22:52 +03:00
|
|
|
self.auth = api_settings.UNAUTHENTICATED_TOKEN()
|
2012-09-20 16:06:27 +04:00
|
|
|
else:
|
2014-12-17 16:22:52 +03:00
|
|
|
self.auth = None
|
2012-09-20 16:06:27 +04:00
|
|
|
|
2017-11-22 13:42:59 +03:00
|
|
|
def __getattr__(self, attr):
|
2012-09-20 16:06:27 +04:00
|
|
|
"""
|
2015-02-09 20:02:54 +03:00
|
|
|
If an attribute does not exist on this instance, then we also attempt
|
|
|
|
to proxy it to the underlying HttpRequest object.
|
2012-09-20 16:06:27 +04:00
|
|
|
"""
|
2015-02-09 20:02:54 +03:00
|
|
|
try:
|
2022-10-07 13:58:38 +03:00
|
|
|
_request = self.__getattribute__("_request")
|
|
|
|
return getattr(_request, attr)
|
2015-02-09 20:02:54 +03:00
|
|
|
except AttributeError:
|
2024-07-17 19:51:39 +03:00
|
|
|
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{attr}'")
|
2015-08-05 19:07:47 +03:00
|
|
|
|
2015-11-04 17:10:51 +03:00
|
|
|
@property
|
|
|
|
def POST(self):
|
|
|
|
# Ensure that request.POST uses our request parsing.
|
|
|
|
if not _hasattr(self, '_data'):
|
2024-07-17 19:51:39 +03:00
|
|
|
with wrap_attributeerrors():
|
|
|
|
self._load_data_and_files()
|
2015-11-04 17:10:51 +03:00
|
|
|
if is_form_media_type(self.content_type):
|
2016-08-15 18:53:17 +03:00
|
|
|
return self._data
|
2015-11-04 17:10:51 +03:00
|
|
|
return QueryDict('', encoding=self._request._encoding)
|
|
|
|
|
2015-08-05 19:07:47 +03:00
|
|
|
@property
|
|
|
|
def FILES(self):
|
2015-08-07 16:24:28 +03:00
|
|
|
# Leave this one alone for backwards compat with Django's request.FILES
|
2015-08-11 18:21:02 +03:00
|
|
|
# Different from the other two cases, which are not valid property
|
|
|
|
# names on the WSGIRequest class.
|
|
|
|
if not _hasattr(self, '_files'):
|
2024-07-17 19:51:39 +03:00
|
|
|
with wrap_attributeerrors():
|
|
|
|
self._load_data_and_files()
|
2015-08-11 18:21:02 +03:00
|
|
|
return self._files
|
2015-08-05 19:07:47 +03:00
|
|
|
|
2016-08-18 16:42:15 +03:00
|
|
|
def force_plaintext_errors(self, value):
|
|
|
|
# Hack to allow our exception handler to force choice of
|
|
|
|
# plaintext or html error responses.
|
|
|
|
self._request.is_ajax = lambda: value
|