restful 和 restframework

 一 。 restful   python

  restful  沒有語言限制,django

     一切皆資源:json

      經過 請求方式知道要作什麼操做 好比(HTTP GET、POST、PUT( 全局更新)/PATCH( 局部更新)、DELETE,還可能包括 HEADER 和 OPTIONS。)後端

  restful (是一種協議,) 一種軟件架構風格、設計風格,而不是標準,只是提供了一組設計原則和約束條件。它主要用於客戶端和服務器交互類的軟件。基於這個風格設計的軟件能夠更簡潔,更有層次,更易於實現緩存等機制。api

  

RESTful的實現:RESTful Web 服務與 RPC 樣式的 Web 服務
瞭解了什麼是REST,咱們再看看RESTful的實現。使用 RPC 樣式架構構建的基於 SOAP 的 Web 服務成爲實現 SOA 最經常使用的方法。RPC 樣式的 Web 服務客戶端將一個裝滿數據的信封(包括方法和參數信息)經過 HTTP 發送到服務器。服務器打開信封並使用傳入參數執行指定的方法。方法的結果打包到一個信封並做爲響應發回客戶端。客戶端收到響應並打開信封。每一個對象都有本身獨特的方法以及僅公開一個 URI 的 RPC 樣式 Web 服務,URI 表示單個端點。它忽略 HTTP 的大部分特性且僅支持 POST 方法。
 
 
二    CBA (View)的請求流程
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
 
 

        十. 解析器

request類

  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數據
相關文章
相關標籤/搜索