zoukankan      html  css  js  c++  java
  • Flask中的CBV

    学完django, 在学flask, 感觉自己在复习django, django真是包罗万象, 

    学习flask前, 先吹捧一下django, 也是没谁了,

    今天来学习一个flask的CBV

    什么是CBV

    说到FBV就是function, 说到CBV就是class

    这样说没毛病, 但是应该学会选择什么时候使用FBV, 什么时候使用CBV

    FBV简单, 小巧, 当不涉及到复杂的逻辑时可以使用FBV

    CBV 灵活, 为什么说灵活呢, 因为, 类的封装, 继承, 多态, 你说灵活不灵活

    定义一个flask中的CBV视图

    class LoginView(views.MethodView):
        def get(self):
            return "LoginView get"
    
        def post(self):
            return "LoginView post"

    CBV有了, 路由在哪里, 之前FBV都是使用装饰器来声明一个路由的, 现在怎么办?

    其实只要看一看@app.route()的源码就会知道该怎么做了.

    @app.route()源码浅解

        def route(self, rule, **options):
            def decorator(f):
                """
                :param f: 视图函数
                :return:  内部函数 decorator
                """
                endpoint = options.pop('endpoint', None)  # 从参数中弹出endpoint, 没有的话就是None
                self.add_url_rule(rule, endpoint, f, **options)  # 调用这个函数, 将路由规则, endpoint, 视图函数传了进去, 其实这里就是去添加路由和视图的对应关系了
                return f
    
            return decorator

    看看是怎么添加路由和视图的对应关系的

        @setupmethod
        def add_url_rule(self, rule, endpoint=None, view_func=None,
                         provide_automatic_options=None, **options):
            """
    
            :param rule: 视图函数的route装饰器中定义的路由规则
            :param endpoint: 从option中取出的endpoint
            :param view_func: 视图函数
            :param provide_automatic_options:
            :param options:
            :return:
            """
           
            if endpoint is None:  # endpoint如果为None
                endpoint = _endpoint_from_view_func(view_func)  # 将试图视图函数传了进去, 返回视图函数的__name__
            options['endpoint'] = endpoint  # 重新赋值endpoint, 这时endpoint有可能等于视图函数的__name__, 或还是之前的值
            methods = options.pop('methods', None)  # 将请求方式弹出
    
          
            if methods is None:
                methods = getattr(view_func, 'methods', None) or ('GET',)
            if isinstance(methods, string_types):
                raise TypeError('Allowed methods have to be iterables of strings, '
                                'for example: @app.route(..., methods=["POST"])')
            methods = set(item.upper() for item in methods)
            required_methods = set(getattr(view_func, 'required_methods', ()))
    
         
            if provide_automatic_options is None:
                provide_automatic_options = getattr(view_func,
                                                    'provide_automatic_options', None)
    
            if provide_automatic_options is None:
                if 'OPTIONS' not in methods:
                    provide_automatic_options = True
                    required_methods.add('OPTIONS')
                else:
                    provide_automatic_options = False
    
            methods |= required_methods
    
            rule = self.url_rule_class(rule, methods=methods, **options)
            rule.provide_automatic_options = provide_automatic_options
    
            self.url_map.add(rule)
            if view_func is not None:
                old_func = self.view_functions.get(endpoint)
                if old_func is not None and old_func != view_func:
                    raise AssertionError('View function mapping is overwriting an '
                                         'existing endpoint function: %s' % endpoint)
                self.view_functions[endpoint] = view_func  # 重要的一句, 看样是是字典增加键值对的操作, key: endpoint: value: func

    打印下view_function

    print(app.view_functions)
    
    {'static': <bound method _PackageBoundObject.send_static_file of <Flask 'flask的CBV'>>, 'login': <function View.as_view.<locals>.view at 0x000001BE77AD1E18>}

    可以看到有一个字典, 里面有两个键值对, 一看就是一个字符串,对应了一个函数或变量, 这些就是url和视图的对应关系, 暂且叫他关系字典吧.

    看到了里就能知道明白之前的两个疑惑

    1.endpoint是做什么的?

    其实就是关系字典的key, 通过endpoint就可以找到对应的视图

    2.为什么视图函数不能重名?

    因为没有endpoint时, 会获取视图的__name__, 就会让视图的__name__来当字典的key, 字典的key肯定是不能重名了, 所以在没有指定endpoint的情况下, 视图不能重名

    回到正题, 看到这里我好想知道怎么添加对应关系了, 看下面一行代码

    app.add_url_rule("/login", endpoint=None, view_func=LoginView.as_view("login"))

    @app.route()调用add_url_rule()来添加对应关系, 那我不能自己调用, 肯定可以的啊.

    as_view()中的参数是必须要传的, 因为会把这个当做关系字典中的key和视图对应

    所以, 这就是一种给CBV添加绑定路由的方式.

    CBV后面也要执行as_view()这和django一样, 甚至连内部的逻辑都是大致相同, 执行完as_view()后return出一个函数, 这个函数会获取对应请求方式的函数, 也就是执行和请求方式对应的函数

    大概来看一看as_view()

        @classmethod
        def as_view(cls, name, *class_args, **class_kwargs):
    
            def view(*args, **kwargs):
                self = view.view_class(*class_args, **class_kwargs)  # 实例化CBV对象
                return self.dispatch_request(*args, **kwargs)
    
            if cls.decorators:
                view.__name__ = name
                view.__module__ = cls.__module__
                for decorator in cls.decorators:
                    view = decorator(view)
    
            # 将参数都封装到FBV view中, 这样通过函数view的空间中就会有这些参数
            view.view_class = cls
            view.__name__ = name
            view.__doc__ = cls.__doc__
            view.__module__ = cls.__module__
            view.methods = cls.methods
            view.provide_automatic_options = cls.provide_automatic_options
            return view  # 将内部函数view返回

    现在再来看看是如何添加路由的

    app.add_url_rule("/login", endpoint=None, view_func=LoginView.as_view("login"))
    
    执行完了as_view()后, 就变成下面的样子了
    app.add_url_rule("/login", endpoint=None, view_func=view)
    这一行代码和FBV难道不一样吗.....一模一样

    这就是CBV

  • 相关阅读:
    java 模拟http请求,通过流(stream)的方式,发送json数据和文件
    $listeners 在vue中的使用 --初学
    vue中关于checkbox数据绑定v-model指令说明
    Vue--理解非prop特性
    Vue里标签嵌套限制问题解决------解析DOM模板时注意事项:
    vue click.stop
    @click.prevent.self和@click.self.prevent区别
    assign()-JS
    摘抄大神对VUE 中slot-scope的深度理解
    oracle11G备份空表解决办法
  • 原文地址:https://www.cnblogs.com/594504110python/p/10140335.html
Copyright © 2011-2022 走看看