路漫漫其修远兮
吾将上下而求索

drf学习:视图cbv和fbv、rest协议、认证源码

时间:2019.2.18

视频:https://www.bilibili.com/video/av28871471/?p=1

博客:http://www.cnblogs.com/wupeiqi/articles/7805382.html

P1day128-01 今日内容概要

P2day128-02 内容回顾

P3day128-03 django视图之CBV基本使用

P4day128-04 django视图之CBV源码流程

P5day128-05 django视图之面试题和csrf补充

P6day128-06 django视图之CBV解决csrf认证

P7day128-07 以上内容梳理

P8day128-08 基于django实现restful api

P9day128-09 restful 协议

P10day128-10 面试题之谈谈你对restful协议的认识

P11day128-11 rest framework框架之认证使用和源码执行流程

P12day128-12 rest framework框架之认证内容梳理

P13day128-13 今日作业

P1day128-01 今日内容概要
面试过程讲解
用drf框架可以更省事
今日概要:
    1、restful规范
    2、drf框架

    
    
P2day128-02 内容回顾
内容回顾:
    1、开发模式:
        - 普通开发模式(前后端放在一起)
        - 前后端分离
            前后端交互都是通过ajax交互
    2、前后端分离优点
        - 当有pc和app两个前端的时候,后端只用维护一套代码,只修改对应的前端就可以
        - 后端逻辑更加清晰
    3、简单的api示例
        创建一个django项目
        下面是url.py里面的文件
        from django.conf.urls import url
        # from django.contrib import admin
        from app01 import views

        urlpatterns = [
            # url(r'^admin/', admin.site.urls),
            url(r'users', users)
        ]

        下面是app01.views里面的文件
        from django.shortcuts import render, HttpResponse
        import json

        def users(request):
            user_list = ['andy', 'bob']
            return HttpResponse(json.dumps(user_list))

        在浏览器里面输入:http://127.0.0.1:8000/users
        就可以实现简单的api接口   
    4、django FBV,CBV
        function base view
        class base view
        
        下面是cbv示例,当用户使用get方法的时候,得到get,使用post方法的时候,得到post,所有的方法都在.as_view里面
        比fbv方便,已经写好了各种方法
        
        创建一个django项目
        下面是url.py里面的文件
        from django.conf.urls import url
        # from django.contrib import admin
        from app01 import views

        urlpatterns = [
            # url(r'^admin/', admin.site.urls),
            url(r'users', views.users),
            url(r'student', views.StudentView.as_view())
        ]       
                
        下面是app01.views里面的文件     

        from django.views import View
        class StudentView(View):
            def get(self, request, *args, **kwargs):
                return HttpResponse('get')
            def post(self, request, *args, **kwargs):
                return HttpResponse('post')
            def put(self, request, *args, **kwargs):
                return HttpResponse('post')
            def delete(self, request, *args, **kwargs):
                return HttpResponse('post')
        
        当使用postman进行post方式测试的时候,需要先将csrf中间件注释,不然错误
    5、列表生成式
        下面的程序作用是分别根据两个类实例化两个对象,然后放到v list里面,下面是简写。v就是一个对象列表
        class Foo:
            pass
        class Bar:
            pass

        v = []
        for i in [Foo, Bar]:
            obj = i()
            v.append(obj)


        v = [item() for item in [Foo, Bar]] 
    
    6、面向对象:封装,继承,多态
        - 封装 
        类可以对同一类的方法封装到一个类。就是最常见的一个类下面多个方法
        类可以将数据封装到对象中。可以通过__init__方法在类生成对象的时候将数据传入到对象中
    
        下面是一个封装示例,结果是True,里面调用了很多层,把对象当做数据传入了
        class Request(object):
            def __init__(self, obj):
                self.obj = obj
            @property
            def user(self):
                return self.obj.authticate()

        class Auth(object):
            def __init__(self, name, age):
                self.name = name
                self.age = age
            def authticate(self):
                return True


        class APIView(object):
            def dispatch(self):
                self.f2()

            def f2(self):
                a = Auth('alex', 18)
                req = Request(a)
                print(req.user)

        obj = APIView()
        obj.dispatch()
    

    
    
P3day128-03 django视图之CBV基本使用
根据不同的请求方法调用不同的函数,是基于反射来处理的


根据url执行as_view()方法,as_view()方法是View类里面的一个方法
url(r'student', views.StudentView.as_view())

views.StudentView.as_view()执行完成后会返回一个函数view,主要就是看这个view

class View(object):
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs):
            #self = StudentView(),cls是当前请求的类。类加括号,实例化对象
            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


看self.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)

    
用户请求进来,请求dispatch,不管是什么请求进来,什么方法,都执行
如果在用户自定义的view里面定义dispatch方法,重载,使用子类同名方法。
下面的方式,不管什么方法请求,返回的都是hello
class StudentView(View):
    def dispatch(self, request, *args, **kwargs):
        return HttpResponse('hello')

下面是自定义的根据反射执行不同的方法,这里返回的要是函数
class StudentView(View):
    def dispatch(self, request, *args, **kwargs):
        func = getattr(self, request.method.lower(), *args, **kwargs)
        ret = func(request, *args, **kwargs)
        return ret
    def get(self, request, *args, **kwargs):
        return HttpResponse('get')
    def post(self, request, *args, **kwargs):
        return HttpResponse('post')
    def put(self, request, *args, **kwargs):
        return HttpResponse('post')
    def delete(self, request, *args, **kwargs):
        return HttpResponse('post')

django已经给我们做好了上面的步骤,可以直接用
可以自己在所有请求执行之前执行某些操作,比如权限等,类似于下面的print函数。也可以使用装饰器实现
class StudentView(View):
    def dispatch(self, request, *args, **kwargs):
        print('before')
        ret = super(StudentView,self).dispatch(request, *args, **kwargs)
        print('after')
        return ret
    def get(self, request, *args, **kwargs):
        return HttpResponse('get')
    def post(self, request, *args, **kwargs):
        return HttpResponse('post')
    def put(self, request, *args, **kwargs):
        return HttpResponse('post')
    def delete(self, request, *args, **kwargs):
        return HttpResponse('post')
        
程序执行过程:url - view方法 - dispatch方法
具体查看图片

dispatch执行过程.png

P4day128-04 django视图之CBV源码流程

多个类公用的功能,可以根据继承来实现,MyBaseView里面的self指的是StudentView这个类,在当前类中找不到dispatch方法的时候,会去其他的父类View中查找
class MyBaseView(object):
    def dispatch(self, request, *args, **kwargs):
        print('before')
        ret = super(MyBaseView,self).dispatch(request, *args, **kwargs)
        print('after')
        return ret


class StudentView(MyBaseView, View):
    def get(self, request, *args, **kwargs):
        return HttpResponse('get')
    def post(self, request, *args, **kwargs):
        return HttpResponse('post')
    def put(self, request, *args, **kwargs):
        return HttpResponse('post')
    def delete(self, request, *args, **kwargs):
        return HttpResponse('post')




P5day128-05 django视图之面试题和csrf补充
django有5类中间件
- process_request
- process_view
- process_response
- process_exception
- process_render_template

用中间件都做过什么
- 权限
- 用户登录验证


当把中间件中的csrf打开后,csrf全局生效
当想让students类中的某个方法不使用csrf功能
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def users(request):
    user_list = ['andy', 'bob']
    return HttpResponse(json.dumps(user_list))


当把中间件中的csrf关闭后,csrf全局失效
当想让students类中的某个方法使用csrf功能
from django.views.decorators.csrf import csrf_protect

@csrf_protect
def users(request):
    user_list = ['andy', 'bob']
    return HttpResponse(json.dumps(user_list))




P6day128-06 django视图之CBV解决csrf认证
cbv实现上面的功能,需要在dispatch方法上面加才可以,加到单独的方法上面无效
from django.views import View
from django.utils.decorators import method_decorator
class StudentView(View):
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        ret = super(StudentView,self).dispatch(request, *args, **kwargs)
        return ret

    def get(self, request, *args, **kwargs):
        return HttpResponse('get')
    def post(self, request, *args, **kwargs):
        return HttpResponse('post')
    def put(self, request, *args, **kwargs):
        return HttpResponse('post')
    def delete(self, request, *args, **kwargs):
        return HttpResponse('post')




P7day128-07 以上内容梳理
P8day128-08 基于django实现restful api
对于普通的路径,如果不通过方法来进行区分,要实现增删改查功能,要四个路径才可以
举了一个例子




P9day128-09 restful 协议
    http://www.cnblogs.com/wupeiqi/articles/7805382.html
    具体查看博客内容
    一般http的状态码有限,表示的内容有限,所以更多的使用自定义的code返回给用户来显示
    

    
P10day128-10 面试题之谈谈你对restful协议的认识
    跨域怎么解决




P11day128-11 rest framework框架之认证使用和源码执行流程
drf:django rest framwork
安装:pip3 install djangorestframework

a、cbv

下面是使用drf的简单示例
from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework.authentication import BaseAuthentication


class StudentView(APIView):
    authentication_classes = [BaseAuthentication,]

    def get(self, request, *args, **kwargs):
        #这个是drf的dispatch方法,而不是django自带的dispatch方法
        #drf的as_view方法里面调用view = super(APIView, cls).as_view(**initkwargs)父类的as_view方法,
        #父类的as_view里面调用了dispatch方法,但是drf里面也有dispatch方法,实际调用drf里面的dispatch方法
        #从这里点进去可以查看dispatch方法的具体执行过程,
        self.dispatch()
        return HttpResponse('get')

    def post(self, request, *args, **kwargs):
        return HttpResponse('post')

    def put(self, request, *args, **kwargs):
        return HttpResponse('post')

    def delete(self, request, *args, **kwargs):
        return HttpResponse('post')


    #具体函数分析
    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 = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?
        #下面的和django自带的功能差不多
        try:
            #下面的方法进行初始化操作,包括权限,认证,限速等操作
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            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)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response


    往里找initialize_request函数增加了额外的属性        
    return Request(
        request,
        parsers=self.get_parsers(),
        authenticators=self.get_authenticators(),  这个是添加了认证类型的变量
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )       

    往里找get_authenticators函数功能
    def get_authenticators(self):
        #返回实例化后的对象列表
        return [auth() for auth in self.authentication_classes]

    往里找authentication_classes这个类为设置的用户在配置文件里面设置的,如果用户在类里面自定义了,则使用用户自定义的
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES


    在用户视图中添加自定义变量,现在的request里面封装了两个,一个是原生的request,一个是[BaseAuthentication,]
    

    查看具体的Request类,看这个类进行实例化的时候进行了什么处理
     return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

    从下面可以看到,原生的request被封装为_request对象,子类中如果想要调用原生的request,使用_request
    class Request(object):
        def __init__(self, request, parsers=None, authenticators=None,
                     negotiator=None, parser_context=None):
            self._request = request
            self.parsers = parsers or ()
            self.authenticators = authenticators or ()


    查看初始化操作做了哪些事情
    def initial(self, request, *args, **kwargs):
        
        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.
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        #下面认证的方法实际调用了user属性
        self.perform_authentication(request)
        
        #下面是检查权限的
        self.check_permissions(request)
        
        #下面是检查访问频率的
        self.check_throttles(request)

        #user属性位置:request.py的189行
        
    @property
    def user(self):
        """
        Returns the user associated with the current request, as authenticated
        by the authentication classes provided to the request.
        """
        if not hasattr(self, '_user'):
            self._authenticate()
        return self._user


    继续查看_authenticate函数,authenticators为BaseAuthentication对象,然后执行authenticate方法。验证是否已经登录。如果已经登录,返回元组。如果没有登录,抛异常
    def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
        for authenticator in self.authenticators:
            try:
                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_classes中,根据上面的执行流程
    就会依次执行这个类里面的authenticator.authenticate(self)方法
    这个类我们可以自己定义,然后到authenticator.authenticate(self)的时候,执行自己的方法
    访问:http://127.0.0.1:8000/students会报没有权限
    访问:http://127.0.0.1:8000/students?token=123带上token才能正常访问
    也就是说只要是需要带认证的都可以类似于这个自己定义
    认证通过后,返回的元组为用户信息,request.user

    from django.shortcuts import HttpResponse
    from rest_framework.views import APIView
    from rest_framework.authentication import BaseAuthentication
    from rest_framework import exceptions


    class MyAuthentication(object):
        def authenticate(self, request):
            token = request._request.GET.get('token')
            if not token:
                raise exceptions.AuthenticationFailed('用户认证失败')
            return ('alex', None)
        def authenticate_header(self, vl):
            pass


    class StudentView(APIView):
        authentication_classes = [MyAuthentication,]

        def get(self, request, *args, **kwargs):
            return HttpResponse('get')

        def post(self, request, *args, **kwargs):
            return HttpResponse('post')



P12day128-12 rest framework框架之认证内容梳理
总结



P13day128-13 今日作业
需要看源码流程,非常重要

未经允许不得转载:江哥架构师笔记 » drf学习:视图cbv和fbv、rest协议、认证源码

分享到:更多 ()

评论 抢沙发

评论前必须登录!