码迷,mamicode.com
首页 > 其他好文 > 详细

Django rest framework 的基本流程(源码分析)

时间:2018-02-05 21:49:08      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:一个   startup   handler   iss   **kwargs   dmi   class   delete   check   

一、基本流程举例:

技术分享图片
urlpatterns = [
    url(r^admin/, admin.site.urls),
    url(r^users/, views.HostView.as_view()),
   
]
urls
技术分享图片
from rest_framework.views import APIView
from rest_framework.response import Response
class HostView(APIView):
    def dispatch(self, request, *args, **kwargs):
        """
        请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法

        注意:APIView中的dispatch方法有好多好多的功能
        """
        return super().dispatch(request, *args, **kwargs)

    def get(self, request, *args, **kwargs):
        return Response(GET请求,响应内容)

    def post(self, request, *args, **kwargs):
        return Response(POST请求,响应内容)

    def put(self, request, *args, **kwargs):
        return Response(PUT请求,响应内容)
Views

二、源码分析:

当我们发送请求后,执行views里面对应的方法时,最开始执行的是dispatch方法

自己定义的dispatch方法(当然自己可以不定义直接应用APIView里面的就可以了,默认就是这种):

    def dispatch(self, request, *args, **kwargs):
        """
        请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法

        注意:APIView中的dispatch方法有好多好多的功能
        """
        return super().dispatch(request, *args, **kwargs)

APIView中的dispatch方法(源码):

    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
        #1.将原来的request进行加工,增加了一些功能,将其放入restframework的Request
        ‘‘‘
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        ‘‘‘

          # 原来request对象,django.core.handlers.wsgi.WSGIRequest
          # 现在的request对象,rest_framework.request.Request

        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            #2.处理版本信息 处理认证信息 处理权限信息 对用户的访问频率进行限制
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            #3.据用户提交的请求方法利用反射获取请求方法
            #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
            #调用具体的方法做具体的操作,
            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        #4.将处理后的response包装
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

1.将原来的request进行加工,增加了一些功能,将其放入restframework的Request

request = self.initialize_request(request, *args, **kwargs)

进入initialize_request函数后:

 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
        )

将这些东西前部都封装在rest_framework的Resquest中,并返回她的对象request,从这以后我们调用的request对象不再是Django提供的request对象了,而是APIView的Resquest的对象,2.处理版本信息 处理认证信息 处理权限信息 对用户的访问频率进行限制

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)

        # Perform content negotiation and store the accepted info on the request
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg

        # Determine the API version, if versioning is in use.
        #2.1处理版本信息
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        #2.2处理认证信息
        self.perform_authentication(request)
        #2.3处理权限信息
        self.check_permissions(request)
        #2.4对用户的访问频率进行限制
        self.check_throttles(request)

3.据用户提交的请求方法利用反射获取请求方法,并改用请求方法实现其具体功能

4.将处理后的response进行包装

三、处理认证的具体分析

当diapatch方法进行到第一步时,我们调用了initialize_request方法将request等封装在Request中顶返回其对象,

    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
        )

authenticators=self.get_authenticators() #用于用户认证 是一个由authentication对象组成的列表

    def get_authenticators(self):
        """
        Instantiates and returns the list of authenticators that this view can use.
        """
        return [auth() for auth in self.authentication_classes]
authentication_classes为一个authentication类组成的列表,他默认是调用
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

当然我们一般是自己定义或者配置到settings中,至此我们的得到authentication对象的列表,其封装在Request对象中,

接的执行第二步

#2.处理版本信息 处理认证信息 处理权限信息 对用户的访问频率进行限制
self.initial(request, *args, **kwargs)
 #2.2处理认证信息
        self.perform_authentication(request)

查看perform_authentication的源码如下

    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

其调用了rest_framework中Request的user方法(这个方法肯定别@property装饰,不然的话不可能直接不加括号的调用)

from rest_framework.request import Request

Request类中的user方法

 @property
    def user(self):
        """
        Returns the user associated with the current request, as authenticated
        by the authentication classes provided to the request.
        """
        #判断当前类中是否有已经认证过的user
        if not hasattr(self, _user):
            #没有认证则去认证
            self._authenticate()
        #认证过了直接返回
        return self._user

注意:user中的self代表的是request对象

没认证的话执行 调用Request类中的_authenticate()方法

 def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
        #遍历request对象中封装的Authentication对象
        for authenticator in self.authenticators:
            try:
                #调用Authentication对象中的authenticate方法,必须要有这个方法不然抛出异常
                #当然Authentication类一般有我们自己定义,实现这个方法就可以了
                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()

认证实例:

局部认证:直接类中定义Authentication类

技术分享图片
from django.db import models

# Create your models here.
class Userinfo(models.Model):
    name=models.CharField(max_length=32,verbose_name=用户名)
    pwd=models.CharField(max_length=32,verbose_name=密码)
    token=models.CharField(max_length=64,null=True)

    def __str__(self):
        return self.name
View Code
urlpatterns = [
    url(r^admin/, admin.site.urls),
    url(r^users/, views.HostView.as_view()),
    url(r^auth/, views.AuthView.as_view()),
]
技术分享图片
import json
import hashlib
import time

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.authentication import SessionAuthentication
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework.exceptions import APIException
from rest_framework.response import Response

from app01 import models


# Create your views here.
class MyAuthentication(object):
    def authenticate(self, request):
        token = request.query_params.get(token)
        user=models.Userinfo.objects.filter(token=token).first()
        if user:
            return (user.name, aaaaaa)
        raise APIException(认证失败)


class AuthView(APIView):
    # 设置为空标识不用认证
    authentication_classes = []

    def get(self, request, *args, **kwargs):
        dic = {code: 1000, msg: ‘‘}
        pwd = request.query_params.get(pwd)
        name = request.query_params.get(name)

        user = models.Userinfo.objects.filter(name=name, pwd=pwd).first()
        if not user:
            dic[msg] = 用户名或密码错误
            dic[code] = 1001
            return Response(dic)
        t = time.time()
        key = %s|%s % (name, t)
        m = hashlib.md5()
        m.update(key.encode(utf-8))
        token = m.hexdigest()

        user.token = token
        user.save()
        dic[token] = token
        dic[msg] = 登陆成功
        return Response(dic)

class HostView(APIView):
    authentication_classes=[MyAuthentication,]
    def dispatch(self, request, *args, **kwargs):
        """
        请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法

        注意:APIView中的dispatch方法有好多好多的功能
        """
        return super().dispatch(request, *args, **kwargs)

    def get(self, request, *args, **kwargs):
        return Response(GET请求,响应内容)

    def post(self, request, *args, **kwargs):
        return Response(POST请求,响应内容)

    def put(self, request, *args, **kwargs):
       
        return Response(PUT请求,响应内容)
Views

全局认证;在settings中配置

技术分享图片
from django.db import models

# Create your models here.
class Userinfo(models.Model):
    name=models.CharField(max_length=32,verbose_name=用户名)
    pwd=models.CharField(max_length=32,verbose_name=密码)
    token=models.CharField(max_length=64,null=True)

    def __str__(self):
        return self.name
models
技术分享图片
urlpatterns = [
    url(r^admin/, admin.site.urls),
    url(r^users/, views.HostView.as_view()),
    url(r^auth/, views.AuthView.as_view()),
]
urls
技术分享图片
from rest_framework.exceptions import APIException
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication

from app01 import models



class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request.query_params.get(token)
        user=models.Userinfo.objects.filter(token=token).first()
        if user:
            return (user.name, aaaaaa)
        raise APIException(认证失败)
utils
技术分享图片
REST_FRAMEWORK = {
    UNAUTHENTICATED_USER: None,
    UNAUTHENTICATED_TOKEN: None,
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "app01.utils.MyAuthentication",
    ],
}
settings中

 

Django rest framework 的基本流程(源码分析)

标签:一个   startup   handler   iss   **kwargs   dmi   class   delete   check   

原文地址:https://www.cnblogs.com/ctztake/p/8419059.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!