restful 和 restframework

 一 。 restful   

  restful  没有语言限制,

     一切皆资源:

      通过 请求方式知道要做什么操作 比如(HTTP GET、POST、PUT( 全局更新)/PATCH( 局部更新)、DELETE,还可能包括 HEADER 和 OPTIONS。)

  restful (是一种协议,) 一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

  

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方法

  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数据
原文地址:https://www.cnblogs.com/xuerh/p/9196657.html