zoukankan      html  css  js  c++  java
  • django rest_framework 框架的使用

    django 的中间件 csrf

    Require a present and correct csrfmiddlewaretoken for POST requests that have a CSRF cookie, and set an outgoing CSRF cookie.

    This middleware should be used in conjunction with the {% csrf_token %}
    template tag.

    • django 的中间件是基于 post 的请求,当post 请求到来的时候 在csrftoken 中间件中执行 process_view 验证 token的正确性,如果验证失败,则返回forbidden 提示给用户。

    • 我们可以让中间件不起作用,首先第一种方法是在配置文件中的settings中注释掉cscftoken的中间件,这样其实存在安全隐患

    • 其次我们可以在我们不需要验证csrftoken的视图view中加装饰器来使我们的视图函数免予csrftoken的校验,使用如下:

    from django.shortcuts import render, HttpResponse
    from django.views import View
    from django.views.decorators.csrf import csrf_exempt, csrf_protect  # csrf_token 单独示例
    from django.utils.decorators import method_decorator
    
    # 基于函数的使用
    @csrf_exempt
    def index(request):
    
        # what you want you view do in this
        return HttpResponse("index")
    
    # 基于类的方式 2-1
    @method_decorator(csrf_exempt, name="dispatch")
    class StudentView(View):
        #方式 2-1
        @method_decorator(csrf_exempt)
        def dispatch(self, request, *args, **kwargs):
            # do something  before diaspatch
            ret =  super(StudentView, self).dispatch(request, *args, **kwargs)
            #do somethig after dispatch
            return ret
        def get(self, request, *args, **kwargs):
            return HttpResponse("GET")
    
        def post(self, request, *args, **kwargs):
            return HttpResponse("POST")
    
    

    django 的CBV模式

    django 中cbv模式中,已类来接受一个请求的到来,通过类继承 view 类
    通过父类的dispatch 方法通过反射 进行请求方法的分发。我们也可以在继承父类的dispatch 方法 来自定制自己的一些操作,rest-framework 也是基于这个实现的,因此我们先看看下他的源码部分:

    首先是url中的配置:

    urlpatterns = [
        re_path('^student/$', views.StudentView.as_view()),
        re_path('^dog/$', views.DogView.as_view()),
    ]
    

    当请求到来的时候,执行as_view() 方法让我们来看下 as_view()做了啥:

        def as_view(cls, **initkwargs):
            """Main entry point for a request-response process."""
            .......
            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的dispatch 方法
            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
    

    再来看看 view类的dispatch 方法:注意可定制的操作前面已经给出

        def dispatch(self, request, *args, **kwargs):
          # 这里的self. http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
            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 的解读

    首先 rest_framework 是为了遵循RESTful 规范而诞生的框架;
    那我们首先需要知道什么是RESTful 规范

    • REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”

    • REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态

    • REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”

    • 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性

    • 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)

    接下来让我们了解下他的API设计规范

    • 1、在url接口中推荐使用Https协议,让网络接口更加安全(Https是Http的安全版,即HTTP下加入 SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL(安全套接层协议))

    • 2、url中可以体现这是个API接口 域名规范

    https://api.example.com 尽量将API部署在专用域名(会存在跨域问题)
    https://example.org/api/ API很简单

    • 3、url中还可以体现版本号,不同的版本可以有不同的接口,使其更加简洁,清晰

    URL,如:https://api.example.com/v1/

    请求头跨域时, 引发发送多次请求

    • 4、restful 提倡面向资源编程,所以在url接口中尽量要使用名词,不要使用动词

    https://api.example.com/v1/zoos

    https://api.example.com/v1/animals

    https://api.example.com/v1/employees

    • 5、此外url中还可以添加条件去筛选匹配

    过滤,通过在url上传参的形式传递搜索条件

    https://api.example.com/v1/zoos?limit=10:指定返回记录的数量

    https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置

    https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数

    https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序

    https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件

    • 6、可以根据Http不同的method,进行不同的资源操作(5种方法:GET / POST / PUT / DELETE
      / PATCH)

    GET :从服务器取出资源(一项或多项)

    POST :在服务器新建一个资源

    PUT :在服务器更新资源(客户端提供改变后的完整资源)

    PATCH :在服务器更新资源(客户端提供改变的属性)

    DELETE :从服务器删除资源

    • 7、响应式应该包含状态码
    200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
    201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
    202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
    204 NO CONTENT - [DELETE]:用户删除数据成功。
    400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
    401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
    403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
    404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
    406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
    410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
    422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
    500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
    
    更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
    
    • 8、应该有返回值,而且格式为统一的json格式
    • 9、应该返回错误信息
    • 10、返回结果中要提供帮助链接,即API最好做到Hypermedia

    django的 rest_framework 组件的使用

    1.首先我们的视图需要时候基于cbv的模式,我们的类需要继承rest_framework的view的 APIView 父类
    如下:

    class DogView(APIView):
        def get(self, request, *args, **kwargs):
            return HttpResponse("GET")
    
        def post(self, request, *args, **kwargs):
            return HttpResponse("POST")
    
    

    接下来让我们研究下APIView的dispath 方法:

        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.
            """
            self.args = args
            self.kwargs = kwargs
            # 对原生的request 加工(丰富)
            """"
            Request(
            request,parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context)
            原生的request = request._request
            """
            # 首先是对原生的request进行了加个处理
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
            self.headers = self.default_response_headers  # deprecate?
    
    

    我们来看下 self.initialize_request 这个方法实现方法

      def initialize_request(self, request, *args, **kwargs):
            """
            Returns the initial request object.
            """
            parser_context = self.get_parser_context(request)
            # self.get_authenticators() seteings配置的一个列表
            # authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
            # 对原生的request第二次加工
            return Request(
                request,
                # 封装了解析器类
                parsers=self.get_parsers(),
                # 封装了用户用户认证的类
                authenticators=self.get_authenticators(),
                # url后缀名的显示方式 ex--> .json
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context
            )
    
    
    1.首先是用户认证 的解析

    在讨论源码之前我先rest_framework配置放在这里(后面需要修改的会加上去):

    # 可以看这里
    
    from rest_framework import settings 
    
    # List of settings that may be in string import notation.
    IMPORT_STRINGS = (
        'DEFAULT_RENDERER_CLASSES',
        'DEFAULT_PARSER_CLASSES',
        'DEFAULT_AUTHENTICATION_CLASSES',
        'DEFAULT_PERMISSION_CLASSES',
        'DEFAULT_THROTTLE_CLASSES',
        'DEFAULT_CONTENT_NEGOTIATION_CLASS',
        'DEFAULT_METADATA_CLASS',
        'DEFAULT_VERSIONING_CLASS',
        'DEFAULT_PAGINATION_CLASS',
        'DEFAULT_FILTER_BACKENDS',
        'DEFAULT_SCHEMA_CLASS',
        'EXCEPTION_HANDLER',
        'TEST_REQUEST_RENDERER_CLASSES',
        'UNAUTHENTICATED_USER',
        'UNAUTHENTICATED_TOKEN',
        'VIEW_NAME_FUNCTION',
        'VIEW_DESCRIPTION_FUNCTION'
    )
    
    

    封住完request之后接下来我们看看后面的源码

      # 进行一系列的认证
      #初始化进入验证,下面来看看initial 这个函数做了啥
        self.initial(request, *args, **kwargs)
    #--------------------------------------------------
      def initial(self, request, *args, **kwargs):
            """
            Runs anything that needs to occur prior to calling the method handler.
            """
            self.format_kwarg = self.get_format_suffix(**kwargs)
            .......
            
            ##  版本的控制的
            version, scheme = self.determine_version(request, *args, **kwargs)
            request.version, request.versioning_scheme = version, scheme
    
            # 认证
            self.perform_authentication(request)
            
            # 权限验证
            self.check_permissions(request)
            
            # 访问频率
            self.check_throttles(request)
    

    接下来讨论 认证方法

    self.perform_authentication(request)源码:

    View 类
     def perform_authentication(self, request):
            """
            Perform authentication on the incoming request.
    
            Note that if you override this and simply 'pass', then authentication
            will instead be performed lazily, the first time either
            `request.user` or `request.auth` is accessed.
            """
            request.user
    
    Request 类
    
        def _authenticate(self):
            """
            Attempt to authenticate the request using each authentication instance
            in turn.
            """
            # 遍历 setting defaults 的列表 的
            """
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.BasicAuthentication'
            
            """
            # 执行每个self.authenticators类中的认证类方法:
            for authenticator in self.authenticators:
                try:
                    # 返回值有三种
                    """
                    1.返回user 与 token 对象(认证成功) 
                    2.返回None(不做处理,交个下一个)
                    3.抛出认证异常(认证失败)
                    """
                    user_auth_tuple = authenticator.authenticate(self)
                except exceptions.APIException:
                    self._not_authenticated()
                    raise
            
                if user_auth_tuple is not None:
                    self._authenticator = authenticator
                    self.user, self.auth = user_auth_tuple
                    return
    
            self._not_authenticated()
    
    

    认证类的写法:

    # Lower 写法
    class MyBasicAuthentication(object):
    
        def authenticate(self, request):
            token = request._request.GET.get("token")
            if token:
                return ("alex",None)
    
            raise exceptions.AuthenticationFailed("failed")
    
        def authenticate_header(self, val):
            pass
    """我们可以继承他的类"""
    # 基于用户token的认证
    from rest_framework.authentication import BasicAuthentication 
    默认的几种用户认证类 自己写的可以继承BasicAuthentication
    1.一中是自己定义类然后在view视图中这要表达:
    authentication_classes=[ yourauthclass, ]
    2.或者全局配置
    
    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":[.......]
    }
    

    接下来是用户权限的控制 这个比较简单直接上rest的自带的几个权限验证的源码类自己研究:

    from rest_framework.permissions import BasePermission
    
    
    class BasePermission(object):
        """
        A base class from which all permission classes should inherit.
        """
        def has_permission(self, request, view):
            """
            Return `True` if permission is granted, `False` otherwise.
            """
            return True
        
        # 这个力度更加细致对于每个用户的管理,后面会将
        def has_object_permission(self, request, view, obj):
            """
            Return `True` if permission is granted, `False` otherwise.
            """
            return True
    
    
    
  • 相关阅读:
    Leetcode 650
    Leetcode 292
    Leetcode 162
    Leetcode 600
    Leetcode 1894
    知识库
    Win2012R2(英文版)开放远程用户登录数量限制的设置
    Win2012R2(英文版)多账号登录,报错:Select a user to disconnect so that you can sign in的处理
    webstorm修改默认浏览器方法
    处理Chrome等浏览器无法上网,但微信能正常使用问题
  • 原文地址:https://www.cnblogs.com/zjcode/p/9410562.html
Copyright © 2011-2022 走看看