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.html

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

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

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

  • 其次咱们能够在咱们不须要验证csrftoken的视图view中加装饰器来使咱们的视图函数免予csrftoken的校验,使用以下:api

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 方法:注意可定制的操做前面已经给出restful

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 规范cookie

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

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

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

  • 全部的数据,不过是经过网络获取的仍是操做(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其余架构风格的最本质属性

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

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

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

  • 二、url中能够体现这是个API接口 域名规范

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

  • 三、url中还能够体现版本号,不一样的版本能够有不一样的接口,使其更加简洁,清晰

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

请求头跨域时, 引起发送屡次请求

  • 四、restful 提倡面向资源编程,因此在url接口中尽可能要使用名词,不要使用动词

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

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

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

  • 五、此外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:指定筛选条件

  • 六、能够根据Http不一样的method,进行不一样的资源操做(5种方法:GET / POST / PUT / DELETE / PATCH)

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

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

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

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

DELETE :从服务器删除资源

  • 七、响应式应该包含状态码
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
  • 八、应该有返回值,并且格式为统一的json格式
  • 九、应该返回错误信息
  • 十、返回结果中要提供帮助连接,即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
相关文章
相关标签/搜索