• 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数据
  • 相关阅读:
    element、vue 使用
    .net bigint,long传到前端发现精度不对
    服务器工具安装
    银行分控模型的建立
    Firebase —— a readymade backend system
    PouchDB —— build applications that work as well offline
    ASP.NET 之 UserRoleIdentity
    insert conflict do update
    【PostgreSQL数据库】PostgreSQL数据库gdb调试子进程
    mac禁用chrome左右双指滑动手势返回上一页
  • 原文地址:https://www.cnblogs.com/xuerh/p/9196657.html
Copyright © 2020-2023  润新知