zoukankan      html  css  js  c++  java
  • Flask快速入门(4) — CBV写法与解析

    方式一:继承View

    from flask import Flask, views
    app = Flask(__name__)
    
    class IndexView(views.View):
        methods = ['GET']
    
        def dispatch_request(self):
            print('index')
            return 'Index!'
    
    app.add_url_rule('/index', view_func=IndexView.as_view(name='name'))
    if __name__ == '__main__':
        app.run()
    

    同django一样,flask中cbv模式时也是需要

    1:自定义一个视图函数类,继承flask.view.View

    2:执行as_view()方法,只不过在这里as_view必须要有一个参数name。这里为什么要有name呢?

    3:在视图函数类中定义dispatch_request方法,为什么必须要写呢该方法呢.

    来看下源码怎么执行,顺便解答一下疑惑。首先是视图类执行as_view方法。先从自定义的类查找,没有再查找父类,即View.as_view()

    as_view()源码分析

    @classmethod  # 是一个类方法,此时cls表示自定义的类IndexView
    def as_view(cls, name, *class_args, **class_kwargs):  # 第一个位置参数没有默认值,所以必须要传
        def view(*args, **kwargs):   # 请求来了执行
            self = view.view_class(*class_args, **class_kwargs)  # cls()实例化一个对象
            return self.dispatch_request(*args, **kwargs)  # 执行dispath_request()方法,如果在自定义类中没有定义该方法,则执行父类的dispatch_request(),点进去其实就是raise NotImplementedError()
    	
        if cls.decorators:
            view.__name__ = name
            view.__module__ = cls.__module__
            for decorator in cls.decorators:
                """在这里对decorators循环遍历,然后再将view函数传入执行。其实就是装饰器"""
                view = decorator(view)
    
        view.view_class = cls
        view.__name__ = name  # 给view函数重命名,这样在该方法 return view时返回的是不同的函数名,遵循路由与视图函数一一对应的元则
        view.__doc__ = cls.__doc__
        view.__module__ = cls.__module__
        view.methods = cls.methods
        view.provide_automatic_options = cls.provide_automatic_options
        return view  # 返回的是一个函数名,这样当请求来的时候执行的就是view()函数 
    

    总结:

    (1)自定义视图类继承flask.views.View时,必须要重写dispatch_request()方法。在该方法中来分发请求方式执行相应的功能

    (2)在as_view()中必须要传一个name参数。就是相当于endpoint起了一个别名用于反向解析路由。有endpoint反向解析用endpoint,没有就用name的值

    (3)不同的路由不能起相同的别名。应遵循路由与视图函数一一对应的元则,比如这样是不行的

    app.add_url_rule('/index', view_func=IndexView.as_view(name='name'))
    app.add_url_rule('/login', view_func=IndexView.as_view(name='name'))
    

    方式二:继承MethodView

    from flask import Flask,views
    
    app = Flask(__name__)
    class IndexView(views.MethodView):
        methods = ['GET','POST']
        def get(self):
            return 'index get method'
    
        def post(self):
            return 'index post method'
    
    app.add_url_rule('/index',view_func=IndexView.as_view(name='hello'))
    if __name__ == '__main__':
        app.run()
    

    从方法一的分析可知,在继承View的自定义视图类中必须要定义dispatch_request方法,在该方法中通过判断请求方式来实现相对应的功能。而在MethodView类中已经帮我们实现了dispatch_request。让我们一起来看一看MethodView的源码:

    class MethodView(with_metaclass(MethodViewType, View)):
        
        def dispatch_request(self, *args, **kwargs):
            # self是自定义的视图类,判断来的请求方式请否允许并获取
            meth = getattr(self, request.method.lower(), None)
            if meth is None and request.method == "HEAD":
                meth = getattr(self, "get", None)
    
            assert meth is not None, "Unimplemented method %r" % request.method
            return meth(*args, **kwargs)  # 比如请求方式为get,到这里就是执行get()
    

    (1)执行as_view()方法。其实还是调用的是View里的as_view,上面已经介绍过了,请求来了就执行dispatch_request方法

    (2)在自定义类中没有dispatch_request方法,所以执行MethodView中的dispatch_request方法

    (3)dispatch_request中判断了请求方式是否允许,以及执行请求

    第二种方式已经帮我们封装好了请求分发的功能,所以是比较推荐的使用方式

  • 相关阅读:
    AJAX
    选择器
    断电原则
    radio为什么不能选择。急急急
    IBase<T>
    委托
    Log4Net
    博弈论 学习笔记
    解决You have new mail in /var/spool/mail/root提示
    Zookeeper分布式安装部署
  • 原文地址:https://www.cnblogs.com/863652104kai/p/11604557.html
Copyright © 2011-2022 走看看