zoukankan      html  css  js  c++  java
  • Flask(10)- 标准类视图

    前言

    • 前面文章讲解 Flask 路由的时候,都是将 URL 路径和一个视图函数关联
    • 当 Flask 框架接收到请求后,会根据请求 URL,调用响应的视图函数进行处理
    • Flask 不仅提供了视图函数来处理请求,还提供了视图类;可以将 URL 路径和一个视图类关联

    标准视图函数

    • 将 URL 路径和一个函数关联,这个函数又被称为视图函数,Flask 框架会根据请求的 URL 调用相应的视图函数进行处理
    • 当访问 127.0.0.1:5000/ 时,index() 函数就会处理该请求,并返回 hello world 字符串
    from flask import Flask
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        return 'hello world'
    
    app.run(debug = True)

    标准视图类

     Flask.views.View  是 Flask 的标准视图类,用户定义的视图类需要继承于  Flask.views.View 。使用视图类的步骤如下:

    1. 用户定义一个视图类,继承于 Flask.views.View;
    2. 在视图类中定义方法 dispatch_request ,处理请求、返回 HTML 文本给客户端;
    3. 使用 app.add_url_rule (rule, view_func) 将 URL 路径和视图类绑定

    最简单的栗子

    #!usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    # author: 小菠萝测试笔记
    # blog:  https://www.cnblogs.com/poloyy/
    # time: 2021/7/13 8:42 下午
    # file: 8_view_class.py
    """
    
    from flask import Flask, views
    from flask.typing import ResponseReturnValue
    
    app = Flask(__name__)
    
    
    # 自定义视图类,继承 views.View
    class view_test(views.View):
        # 返回一个字符串给客户端
        def dispatch_request(self) -> ResponseReturnValue:
            return "hello world"
    
    
    # 将路由规则 / 和视图类 view_test 进行绑定
    app.add_url_rule(rule="/", view_func=view_test.as_view("view"))
    
    if __name__ == '__main__':
        app.run()

    重点 as_view

    •  view_test.as_view("view")  代表创建了一个名称为 view 的视图函数
    • app.add_url_rule 实际上是将路由规则和视图函数(由视图类的 as_view 方法转换而来)绑定

    浏览器访问的效果

    as_view 函数

    视图类的本质是视图函数,函数 View.as_view () 会返回一个视图函数

    简化版

    为了更清晰理解 as_view 函数的功能,自行实现一个简化版本的 as_view 函数

    #!usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    # author: 小菠萝测试笔记
    # blog:  https://www.cnblogs.com/poloyy/
    # time: 2021/7/13 8:42 下午
    # file: 8_view_class.py
    """
    
    from flask import Flask, views
    from flask.typing import ResponseReturnValue
    
    app = Flask(__name__)
    
    class view_test2(views.View):
    
        def dispatch_request(self) -> ResponseReturnValue:
            return {"msg": "success", "code": 0}
    
        @staticmethod
        def as_view(name, **kwargs):
            view = view_test2()
            return view.dispatch_request
    
    
    # 将路由规则 / 和视图类 view_test 进行绑定
    app.add_url_rule(rule="/", view_func=view_test2.as_view("view"))
    
    if __name__ == '__main__':
        app.run()
    1. 定义了一个静态方法 as_view,它首先创建一个实例 view
    2. 然后返回实例 view 的 dispatch_request 方法
    3. 即 view_func 指向了实例 view 的方法 dispatch_request
    4. 当访问页面路径 / 时,最终会调用 index.dispatch_request ()

    继承

    使用类视图的好处是支持继承,可以把一些共性的东西放在父类中,其他子类可以继承

    父类 baseview

    #!usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    # author: 小菠萝测试笔记
    # blog:  https://www.cnblogs.com/poloyy/
    # time: 2021/7/13 10:15 下午
    # file: s8_baseview.py
    """
    
    from flask import Flask, views, render_template
    
    app = Flask(__name__)
    
    
    class BaseView(views.View):
       # 如果子类忘记定义 get_template 就会报错
        def get_template(self):
            raise NotImplementedError()
        
       # 如果子类忘记定义 get_data 就会报错
        def get_data(self):
            raise NotImplementedError()
    
        def dispatch_request(self):
            # 获取模板需要的数据
            data = self.get_data()
            # 获取模板文件路径
            template = self.get_template()
            # 渲染模板文件
            return render_template(template, **data)

      

    子类 userview

    #!usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    # author: 小菠萝测试笔记
    # blog:  https://www.cnblogs.com/poloyy/
    # time: 2021/7/13 10:15 下午
    # file: 8_userview.py
    """
    from s8_baseview import BaseView
    
    
    class UserView(BaseView):
        def get_template(self):
            return "user.html"
    
        def get_data(self):
            return {
                'name': 'zhangsan',
                'gender': 'male',
            }

    app.py 应用主入口

    #!usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    # author: 小菠萝测试笔记
    # blog:  https://www.cnblogs.com/poloyy/
    # time: 2021/7/13 10:31 下午
    # file: 8_app.py
    """
    
    from flask import Flask, views
    
    from s8_userview import UserView
    
    app = Flask(__name__)
    
    app.add_url_rule('/user/', view_func=UserView.as_view('UserView'))
    app.run(debug=True)

    user.html 代码

    <html>
    <body>
    <h2>name = {{ name }}</h2>
    <h2>gender = {{ gender }}</h2>
    </body>
    </html>

    浏览器访问的效果

    使用装饰器

    在视图函数、视图类中使用装饰器还是一大杀器

    检查登录功能

    不使用装饰器前的代码

    def check_login():
        if 用户已经登录:
            return True
        else:        
            return False
    
    @app.route('/page1', page1)
    def page1():
        if not check_login():
            return '请先登录'
        执行 page1 的功能
    
    @app.route('/page2', page2)
    def page2():
        if not check_login():
            return '请先登录'
        执行 page2 的功能
    • 在处理 /page1 和 /page2 时需要检查登录,在函数 page1 () 和 page2 () 的头部调用 check_login 函数
    • 这种方法虽然实现了功能,但不够简洁

    检查登录的装饰器

    使用装饰器实现登录的功能,定义检查登录的装饰器 check_login

    from flask import request
    
    from functools import wraps
    
    def check_login(original_function):
        @wraps(original_function)
        def decorated_function(*args, **kwargs):
            user = request.args.get("user")
            if user and user == "zhangsan":
                return original_function(*args, **kwargs)
            else:
                return "请登录"
    
        return decorated_function()
    • 装饰器 check_login 本质是一个函数
    • 它的输入是一个函数 original_function
    • 它的输出也是一个函数 decorated_function
    • original_function 是原先的处理 URL 的视图函数,它不包含检查登录的功能逻辑,就是到时候需要添加装饰器的函数
    • decorated_function 是在 original_function 的基础上进行功能扩充的函数(这就是装饰器的功能),它首先检查是否已经登录,如果已经登录则调用 original_function,如果没有登录则返回错误
    • 使用 functools.wraps (original_function) 保留原始函数 original_function 的属性

    在视图函数中使用装饰器

    #!usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    # author: 小菠萝测试笔记
    # blog:  https://www.cnblogs.com/poloyy/
    # time: 2021/7/13 10:31 下午
    # file: 8_app.py
    """
    
    from flask import Flask, request
    from functools import wraps
    
    app = Flask(__name__)
    
    # 定义装饰器
    def check_login(original_function):
        @wraps(original_function)
        def decorated_function(*args, **kwargs):
            user = request.args.get("user")
            if user and user == "zhangsan":
                return original_function(*args, **kwargs)
            else:
                return "请登录"
    
        return decorated_function()
    
    
    @app.route("/page1")
    @check_login
    def page1():
        return "page1"
    
    
    @app.route("/page2")
    @check_login
    def page2():
        return "page2"
    
    
    app.run(debug=True)
    • page1、page2 两个视图函数更关注请求处理,而检查登录的功能交给装饰器去负责
    • 这样,检查登录的功能与 page1 和 page2 本身的功能是分离的

    浏览器访问的效果

    在视图类中使用装饰器

    #!usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    # author: 小菠萝测试笔记
    # blog:  https://www.cnblogs.com/poloyy/
    # time: 2021/7/13 11:06 下午
    # file: 8_viewclass_decorated.py
    """
    
    from flask import Flask, request, views
    from functools import wraps
    
    app = Flask(__name__)
    
    
    def check_login(original_function):
        @wraps(original_function)
        def decorated_function(*args, **kwargs):
            user = request.args.get("user")
            if user and user == 'zhangsan':
                return original_function(*args, **kwargs)
            else:
                return '请先登录'
    
        return decorated_function
    
    
    class Page1(views.View):
        decorators = [check_login]
    
        def dispatch_request(self):
            return 'Page1'
    
    
    class Page2(views.View):
        decorators = [check_login]
    
        def dispatch_request(self):
            return 'Page2'
    
    
    app.add_url_rule(rule='/page1', view_func=Page1.as_view('Page1'))
    app.add_url_rule(rule='/page2', view_func=Page2.as_view('Page2'))
    app.run(debug=True)

    decorators = [check_login] 设定视图类的装饰器

  • 相关阅读:
    vue六十五:vuex-getters和vuex-mapGetters
    vue六十四:vuex-mapStore
    vue六十三:vuex的异步处理
    vue六十二:vuex的同步状态管理和调试工具vue-devtools
    vue六十一:使用vuex管理状态示例
    vue六十:电影院售票项目案例之影院页面和使用Better-Scroll实现拖拉滚动
    vue五十九:电影院售票项目案例之详情页面
    vue五十八:电影院售票项目案例之项目吸顶效果
    ingress 413 Request Entity Too Large
    kubeadm搭建K8S集群
  • 原文地址:https://www.cnblogs.com/poloyy/p/15008909.html
Copyright © 2011-2022 走看看