一 。 restful python
restful 沒有語言限制,django
一切皆資源:json
經過 請求方式知道要作什麼操做 好比(HTTP GET、POST、PUT( 全局更新)/PATCH( 局部更新)、DELETE,還可能包括 HEADER 和 OPTIONS。)後端
restful (是一種協議,) 一種軟件架構風格、設計風格,而不是標準,只是提供了一組設計原則和約束條件。它主要用於客戶端和服務器交互類的軟件。基於這個風格設計的軟件能夠更簡潔,更有層次,更易於實現緩存等機制。api
def as_view(cls, **initkwargs): """ Main entry point for a request-response process. """ for key in initkwargs: if key in cls.http_method_names: raise TypeError("You tried to pass in the %s method name as a " "keyword argument to %s(). Don't do that." % (key, cls.__name__)) if not hasattr(cls, key): raise TypeError("%s() received an invalid keyword %r. as_view " "only accepts arguments that are already " "attributes of the class." % (cls.__name__, key)) def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) view.view_class = cls view.view_initkwargs = initkwargs # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view
1.項目加載 執行 as_view() 函數瀏覽器
2. as_view() 本身沒有找父類(View)去要緩存
3.as_view方法, return 一個函數名(view) view函數在as_view方法裏面 服務器
4. 服務端接收玩一個請求才 執行view方法restful
4. 執行view函數 返回一個 return self.dispatch(request, *args, **kwargs) 架構
5. dispatch函數
看你什麼請求執行對應的函數
def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. 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 return handler(request, *args, **kwargs)
三 用rest_framework 組件, 要在 INSTALLED_APPS 中配置中加一句
"rest_frameword"
四. APIView的請求流程;
1. APIView 繼承 View類
2. 項目加載執行APIView 中的有as_view 方法, 返回的是一個它父類的(View) view 函數 等待用戶發送請求方式調用
4 .用戶 發送一個GET請求到後端, 走url(r'^books/', views.BookDetailView.as_view()), 執行View 函數
5. view中 as_view執行view函數 返回一個 return self.dispatch(request, *args, **kwargs)
6.dispatch方法APIView本身有因此就用本身的
7. dispatch中的
request = self.initialize_request(request, *args, **kwargs)
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 ) 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. """ 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
self.request = request
8. 在BookDetailView中調用:
request._request.GET 就是 request.GET
jango 中爲了方便request._request.GET 能夠簡寫爲 request.GET
五 rest_framework中的ModelViewSet 視圖
ps:由於有兩個GET請求,若是還用之前的執行請求的方式,就不行了,就要用ModelViewSet ,
把請求方式設爲KEY,對應不一樣的Value函數名,就解決了這個問題。
能夠簡便的實現restful協議的查(查看所有數據),增,單一的改,查,刪
視圖代碼
from rest_framework.viewsets import ModelViewSet class AuthorsModelView(ModelViewSet): queryset = Author.objects.all() serializer_class = AuthorModelSerializers
url 路徑代碼
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), # 五個功能用同一個類 url(r'^book/$',views.AuthorsModelView.as_view({"get": "list", "post": "create"})), url(r"^book/(?P<pk>\d+)/$", views.AuthorsModelView.as_view({ "get": "retrieve", "put": "update", "delete": "destroy", })) ]
(1) ModelViewSet繼承了五個類源碼pass
class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): """ A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions. """ pass
(2) 項目加載執行as_view()函數,
(3) as_view() 本身沒有找父類(GenericViewSet,GenericViewSet父類ViewSetMixin中有一個 as_view方法),返回一個view函數名
(4)等服務器收到一個請求在執行view函數吧參數傳給action這個默認參數接收,吧參數字典循環出來,經過steattr操做 後面執行
請求函數就是以後它的Value函數,
(5) Value 對應的函數在繼承的 這五個類中
mixins.CreateModelMixin,
mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin,
六 。 rest_framework 認證組件 請求流程
·
1. 認證組件繼承APIView,APIView 繼承 View類
2. 項目加載執行APIView 中的有as_view 方法, 返回的是一個它父類的(View) view 函數 等待用戶發送請求方式調用
3. 用戶發送請求到服務端,執行view方法, view方法中調用dispatch方法,APIView有用APIView的,
4 APIView 在分發請求以前 執行 self.initial(request, *args, **kwargs)
5.self.initial(request, *args, **kwargs) 調用這個方法執行這個方法中的認證組件你方法 self.perform_authentication(request)
6. self.perform_authentication(request)方法中調用 request.user 這個靜太方法
7. 找這個request.user 在self.initialize_request(request, *args, **kwargs) 方法中的Request的類中,執行request.user方法,在這個方法中調用Request的類中 self._authenticate(self) 方法
8._authenticate 這類中循環一個for authenticator in self.authenticators:
9.self.authenticators 是self.authenticators = authenticators or () 賦的值
10.authenticators 是 調用Request 這個類中傳的參數
Request( request, parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context )
11.self.get_authenticators() 這個方法 的返回值賦值給 authenticators,調用 get_authenticators() 這個方法返回的是一個列表推到式 return [auth() for auth in self.authentication_classes]
12 authentication_classes 就是你本身寫的想要認證的類 對應的是視圖中的 authentication_classes = [ "寫本身想要認證的類" ]
13. 因此 第八步驟_authenticate 這類中循環一個for authenticator in self.authenticators: 循環的 是你本身想要認證的類循環中 user_auth_tuple = authenticator.authenticate(self) 調用authenticate(self) , authenticate(self) 方法 視圖中有所及就執行、
14. 執行視圖中的 authenticate(self) , 必須返回兩個值,源碼才能收到,或者 拋出異常 保持根源嗎一致
15 。authentication_classes 作了哪些操做才能接收你想要認證的類。
ps , 在項目settings 中加一個
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":(
"app01.service.auth.AuthUser",
)
}
16 api_settings.DEFAULT_AUTHENTICATION_CLASSES執行這個方法, api_settings,中根本沒有DEFAULT_AUTHENTICATION_CLASSES方法, 可是有def __getattr__(self, attr) 方法, attr 就是DEFAULT_AUTHENTICATION_CLASSES, 走到 if attr not in self.defaults: self.defaults】不是空不符合if條件 接着走val = self.user_settings [attr] 拆開來看, 而後 調用user_settings方法
17. 執行user_settings方法, user_settings方法, self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})找本身在settings中設置的值,找不到返回一個空字典,
18, 把返回值賦值給 valsetattr(self, attr, val) 之後再調用DEFAULT_AUTHENTICATION_CLASSES 就是調用"app01.service.auth.AuthUser return val 返還給 api_settings.DEFAULT_AUTHENTICATION_CLASSES 再賦值authentication_classes 之後這個app下的表都認證就能夠了
class AuthorsModelView(ModelViewSet): authentication_classes = [ "寫本身想要認證的類" ] queryset = Author.objects.all() serializer_class = AuthorModelSerializers ################################---Login----############################ from app01.models import User,UserToken def get_random_str(user): import hashlib,time ctime=str(time.time()) md5=hashlib.md5(bytes(user,encoding="utf8")) md5.update(bytes(ctime,encoding="utf8")) return md5.hexdigest() from django.http import JsonResponse class LoginViewSet(APIView): def post(self,request,*args,**kwargs): res={"code":200,"msg":None} try: user=request.data.get("user") pwd=request.data.get("pwd") user_obj=User.objects.filter(name=user,pwd=pwd).first() print(user,pwd,user_obj) if not user_obj: res["code"]=405 res["msg"]="用戶名或者密碼錯誤" else: token=get_random_str(user) UserToken.objects.update_or_create(user=user_obj,defaults={"token":token}) res["token"]=token except Exception as e: res["code"]=1002 res["msg"]=e return JsonResponse(res,json_dumps_params={"ensure_ascii":False})
關於認證的總結:
1 認證失敗,拋異常
2 認證成功:
若是是最後一次認證,返回元組,若是不是,返回None。
七 ,權限組件和頻率組件 和認證組件 大致相同
1. 權限代碼
在app01.service.permissions.py中:
from rest_framework.permissions import BasePermission class SVIPPermission(BasePermission): message="SVIP才能訪問!" def has_permission(self, request, view): if request.user.user_type==3: return True return False
在views.py:
from app01.service.permissions import * class BookViewSet(generics.ListCreateAPIView): permission_classes = [SVIPPermission,] queryset = Book.objects.all() serializer_class = BookSerializers
settings.py配置以下:
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",] }
2 。 頻率組件代碼
在app01.service.throttles.py中:
from rest_framework.throttling import BaseThrottle VISIT_RECORD={} class VisitThrottle(BaseThrottle): def __init__(self): self.history=None def allow_request(self,request,view): remote_addr = request.META.get('REMOTE_ADDR') print(remote_addr) import time ctime=time.time() if remote_addr not in VISIT_RECORD: VISIT_RECORD[remote_addr]=[ctime,] return True history=VISIT_RECORD.get(remote_addr) self.history=history while history and history[-1]<ctime-60: history.pop() if len(history)<3: history.insert(0,ctime) return True else: return False def wait(self): import time ctime=time.time() return 60-(ctime-self.history[-1])
在views.py:
from app01.service.permissions import *
class BookViewSet(generics.ListCreateAPIView): permission_classes = [SVIPPermission,] queryset = Book.objects.all() serializer_class = BookSerializers
settings.py配置以下:
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",] # 頻率組件 }
八. rest_framework 中的URL 路由
from rest_framework import routers from app01 import views routers=routers.DefaultRouter() routers.register("authors",views.AuthorsModelView) routers.register("publishes",views.PublishModelView) routers.register("books",views.BookModelView) urlpatterns = [ url(r'^admin/', admin.site.urls), # url(r'^index/',index), url(r"^",include(routers.urls)),
九. rest_framework中的分頁
簡單分頁 比較經常使用
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination class PNPagination(PageNumberPagination): page_size = 1 page_query_param = 'page' page_size_query_param = "size" max_page_size = 5 class BookViewSet(viewsets.ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializers def list(self,request,*args,**kwargs): book_list=Book.objects.all() pp=LimitOffsetPagination() pager_books=pp.paginate_queryset(queryset=book_list,request=request,view=self) print(pager_books) bs=BookSerializers(pager_books,many=True) #return Response(bs.data) return pp.get_paginated_response(bs.data)
from rest_framework.pagination import LimitOffsetPagination
jango的request類和rest-framework的request類的源碼解析
(通常默認就能夠)
from rest_framework.parsers import JSONParser,FormParser class PublishViewSet(generics.ListCreateAPIView): parser_classes = [FormParser,JSONParser] queryset = Publish.objects.all() serializer_class = PublshSerializers def post(self, request, *args, **kwargs): print("request.data",request.data) return self.create(request, *args, **kwargs)
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",], "DEFAULT_THROTTLE_RATES":{ "visit_rate":"5/m", }, "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',] }
1. 不寫用默認便可
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer class BookView(APIView): renderer_classes = [JSONRenderer]
若是是瀏覽器訪問就返回HTML頁面,若是不是就返回一個JSon數據