目錄
一、DRF框架 - Django REST Framework
2-1 as_view方法源碼 - 局部禁用Django自帶的csrf組件
2-2 dispatch - 使用APIview的dispatch進行請求分發處理,對request進行了處理
2-3 initialize_request - 返回新處理的request,既包含了原有屬性又增加了相應屬性
2-4 request - 對request進行處理,getattr和setattr的處理
2-4-1 __getattr__處理對DRF內request內不存在屬性的請求
2-4-2 request.data - 存儲前臺傳輸原body體內數據
2-4-3 request.query_params - 存儲原始GET內數據
一、DRF框架 - Django REST Framework
1-1 DRF框架介紹 - 官方文檔
Django REST框架是用於構建Web api的強大而靈活的工具包,即Django內置模塊的拓展,可視爲Django的第三方APP插件包。
- Web可瀏覽API對於開發人員來說是一個巨大的可用性勝利。
- 身份驗證策略,包括OAuth1a和OAuth2的包。
- 同時支持ORM和非ORM數據源的序列化。
- 可自定義的——如果不需要更強大的功能,只需使用常規的基於功能的視圖。
- 豐富的文檔和強大的社區支持。
- 得到Mozilla、Red Hat、Heroku、Eventbrite等國際知名公司的使用和信任。
1-2 安裝
- 方式一:pip3 install djangorestframework
- 方式二:pycharm圖形化界面安裝
- 方式三:pycharm命令行下安裝(裝在當前工程所用的解釋器下)
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', # 組件註冊 'rest_framework', ]
二、APIview源碼分析
2-1 as_view方法源碼 - 局部禁用Django自帶的csrf組件
@classmethod def as_view(cls, **initkwargs): """ Store the original class on the view function. This allows us to discover information about the view when we do URL reverse lookups. Used for breadcrumb generation. 將原始類存儲在視圖函數中。這允許我們在執行URLreverse查找時發現關於視圖的信息。用於生成導航。 """ if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet): def force_evaluation(): raise RuntimeError( 'Do not evaluate the `.queryset` attribute directly, ' 'as the result will be cached and reused between requests. ' 'Use `.all()` or call `.get_queryset()` instead.' ) cls.queryset._fetch_all = force_evaluation view = super(APIView, cls).as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. # 局部禁用Django自帶的csrf組件 return csrf_exempt(view)
2-2 dispatch - 使用APIview的dispatch進行請求分發處理,對request進行了處理
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. ' .dispatch() '與Django的常規調度非常相似, 但是有額外的鉤子用於啓動、finalize和異常處理。 """ self.args = args self.kwargs = kwargs # request參數爲原始request,以及後續有名分組等傳輸參數 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
2-3 initialize_request - 返回新處理的request,既包含了原有屬性又增加了相應屬性
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. 返回初始請求對象。 """ parser_context = self.get_parser_context(request) # 類實例化產生了對象,產生新的DRF的request return Request( request, # 用於解析(獲取解析器) parsers=self.get_parsers(), # 用於認證 authenticators=self.get_authenticators(), # 用於分頁 negotiator=self.get_content_negotiator(), # 用於解析 parser_context=parser_context )
2-4 request - 對request進行處理,getattr和setattr的處理
class Request(object): """ Wrapper allowing to enhance a standard `HttpRequest` instance. Kwargs: - request(HttpRequest). The original request instance. - parsers_classes(list/tuple). The parsers to use for parsing the request content. - authentication_classes(list/tuple). The authentications used to try authenticating the request's user. 包裝器允許增強一個標準的HttpRequest實例。 Kwargs: -請求(HttpRequest)。原始請求實例。 - parsers_classes(列表/元組)。用於解析的解析器請求的內容。 = authentication_classes(列表/元組)。用於嘗試的驗證驗證請求的用戶。 """ 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__) ) self._request = request 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,)
2-4-1 __getattr__處理對DRF內request內不存在屬性的請求
def __getattr__(self, attr): """ 位於request類內 實現效果:若外部調用DRF內不存在的屬性,會去_request查找,_request在init內被賦予原始request If an attribute does not exist on this instance, then we also attempt to proxy it to the underlying HttpRequest object. 如果這個實例上不存在屬性,那麼我們也會嘗試將其代理到底層HttpRequest對象。 """ try: # getattr獲取self._request內attr屬性的值,若找不到屬性 自動返回None return getattr(self._request, attr) except AttributeError: return self.__getattribute__(attr)
2-4-2 request.data - 存儲前臺傳輸原body體內數據
@property def data(self): '''request內方法,被@property隱藏爲屬性使用''' if not _hasattr(self, '_full_data'): self._load_data_and_files() return self._full_data
2-4-3 request.query_params - 存儲原始GET內數據
@property def query_params(self): """ More semantically correct name for request.GET. """ return self._request.GET
三、使用DRF的簡單數據操作
from rest_framework.views import APIView class Books(APIView): # rest_framework.request下的Request作爲參數傳入 def put(self, request, pk): # django.core.handlers.wsgi.WSGIRequest----原來的djagno中的request的類 # 現在的request已經成了:rest_framework.request.Request # print(request.PUT) # 以後再取數據,直接從request.data中取 print(request.data) # 前端傳過來的編碼格式:json格式:{'name': '水都是', 'price': '15'} # 前端傳過來的編碼格式:urlencoded格式:<QueryDict: {'name': ['紅樓夢'], 'price': ['15']}> # request.data是誰的對象? # request.data不同編碼格式過來,它可能是不同類的對象,但是用法是一樣的 # 原來的request是:request._request print(type(request._request)) # 由於__getattr__可以直接使用原有方式獲取數據 # 下列二者相同,也能取出來(method,GET,POST,BODY) print(request._request.GET) print(request.GET) return JsonResponse({'status': 100, 'msg': '修改成功'})