請求模塊
主要是分析 drf 二次封裝后的 request 對象
以及怎么拿到請求傳遞過來的數據(url 拼接的數據,數據包傳過來的數據)
源碼分析
源碼查看,從 as_view 進到 APIView 類的 dispatch 方法,dispatch 中的 request = self.initialize_request(request, *args, **kwargs)
中入手
rest_framework.views.APIView#dispatch
# ...
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
# 請求模塊
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
# 三大認證模塊
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
rest_framework.views.APIView#initialize_request
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
rest_framework.request.Request#__init__
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
assert isinstance(request, HttpRequest), (
'The `request` argument must be an instance of '
'`django.http.HttpRequest`, not `{}.{}`.'
.format(request.__class__.__module__, request.__class__.__name__)
)
# 二次封裝 request,將原生 request 作為 drf request 對象的 _request 屬性
self._request = request
# 雖然 drf 對 request 對象做了二次封裝,但是它也做了完全兼容(見下面的 __getattr__ 方法)
self.parsers = parsers or ()
self.authenticators = authenticators or ()
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = Empty
self._files = Empty
self._full_data = Empty
self._content_type = Empty
self._stream = Empty
if self.parser_context is None:
self.parser_context = {}
self.parser_context['request'] = self
self.parser_context['encoding'] = request.encoding or settings.DEFAULT_CHARSET
force_user = getattr(request, '_force_auth_user', None)
force_token = getattr(request, '_force_auth_token', None)
if force_user is not None or force_token is not None:
forced_auth = ForcedAuthentication(force_user, force_token)
self.authenticators = (forced_auth,)
rest_framework.request.Request#__getattr__
做了特殊兼容
def __getattr__(self, attr):
"""
If an attribute does not exist on this instance, then we also attempt
to proxy it to the underlying HttpRequest object.
"""
try:
# 對原有的 request 做了完全兼容
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
正式使用
--> 所以在 APIView 視圖類的方法中我們可以這樣寫
所以以后
- url 拼接的參數都可以用
request.query_params
來取- 所有請求的數據包方式數據都可以用
request.data
來取,所有數據方式(from-data、json...)它都做解析了
class Test(APIView):
def get(self, request, *args, **kwargs):
# 獲取 url 拼接的參數
print(request._request.GET) # 二次封裝
print(request.GET) # 兼容
print(request.query_params) # 擴展,推薦用這個
return Response("drf get ok.")
def post(self, request, *args, **kwargs):
# 獲取 url 拼接的參數 (所有請求方式都可以攜帶這個)
print(request._request.GET)
print(request.GET) # 兼容
print(request.query_params) # 擴展,推薦用這個
# 獲取 post 參數
print(request._request.POST) # 拿不到 json 的數據
print(request.POST) # 兼容,拿不到 json 的數據
print(request.data) # 擴展,兼容性最強,三種數據方式都可以,推薦用這個
return Response("drf post ok")
總結
- drf 對原生 request 做了二次封裝,
request._request
就是原生 request - 原生 request 對象的屬性和方法都可以被 drf 的 request 對象直接訪問(向下兼容)
- drf 請求的所有 url 拼接參數都被解析到
request.query_params
中,所有數據包數據都被解析到request.data
中
任何請求都可以通過 url 拼接參數來傳遞參數,同樣通過 request.query_params
獲取