Flask - 标准类视图
一、前言
参考https://www.cnblogs.com/poloyy/p/15008909.html,http://www.imooc.com/wiki/flasklesson/flaskview.html
- 前面文章讲解 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。使用视图类的步骤如下:
- 用户定义一个视图类,继承于 flask.views.View;
- 在视图类中定义方法 dispatch_request,处理请求、返回 HTML 文本给客户端;
- 使用 app.add_url_rule (rule, view_func) 将 URL 路径和视图类绑定
下面是视图类的例子app.py
from flask import Flask, views app = Flask(__name__) class Index(views.View) : def dispatch_request(self): return 'hello world' app.add_url_rule(rule='/', view_func = Index.as_view('Index')) app.run(debug = True)
在第 4 行,定义视图类 Index 用于处理路径为 / 的 URL,视图类 Index 继承于 Flask.views.View;在第 5 行,定义方法 dispatch_request,该方法返回 ‘hello world’ 给客户端;在第 8 行,将路径为 / 的 URL 和视图类 Index 绑定。
Tips:Index.as_view (‘Index’) 创建一个名称为 Index 的视图函数,app.add_url_rule 实际上是将 URL 路径和视图函数(由视图类的 as_view 转换而来)绑定。
函数 View.as_view () 返回一个视图函数
四、继承
使用类视图的好处是支持继承,可以把一些共性的东西放在父类中,其他子类可以继承。下面通过一个例子 inherit.py 说明如何使用继承。
4.1 父类 BaseView
首先,定义视图类 BaseView,它继承于 flask.views.View,它是用户自定义的视图类的父类,app.py代码如下:
from flask import Flask, views, render_template app = Flask(__name__) class BaseView(views.View): def get_template(self): raise NotImplementedError() def get_data(self): raise NotImplementedError() def dispatch_request(self): data = self.get_data() template = self.get_template() return render_template(template,**data)
BaseView 与子类之间的关系如下:BaseView 提供了 dispatch_request 方法的实现,子类继承了这个方法,不需要重新实现 dispatch_request;BaseView 定义了两个接口函数 get_template 和 get_data,子类必须实现这两个方法。
在 BaseView 中,get_template 和 get_data 的缺省实现是抛出错误 NotImplementedError,如果子类忘记定义了这两个方法,在运行时会报错。
在 BaseView 中,定义了方法 displach_request (),调用 get_template () 获得模板的路径,调用 get_data () 获取模板的参数,最后调用 render_template 根据模板路径 template 和模板参数 data 渲染输出。
4.2 子类 UserView
实现子类 UserView,它继承于 BaseView,user.py代码如下:
from app import BaseView from flask import Flask app = Flask(__name__) class UserView(BaseView): def get_template(self): return "index.html" def get_data(self): return { 'name': "zhangsan", 'age':13 } app.add_url_rule('/user/',view_func=UserView.as_view('UserView')) if __name__ == '__main__': app.run(debug=True)
在子类 UserView 中,get_template 返回模板路径为 ‘user.html’,get_data 返回模板参数 name 和 gender。BaseView 中已经实现了视图类的 dispatch_request 方法,子类 UserView 继承了 BaseView 的 dispatch_request 方法,因此不需要再重新实现该方法。
将路径为 /user/ 的 URL 和视图类 UserView 绑定,当访问路径为 /user/ 的 URL 时,最终由 BaseView.dispatch_request 进行处理。
4.3 模板 user.html
在templates目录下创建模板 index.html:
<html> <body> <h2>name = {{ name }}</h2> <h2>age = {{ age }}</h2> </body> </html>
4.4 运行结果
在浏览器中访问http://127.0.0.1:5000/user/,显示如下:
五、使用装饰器
5.1 检查登录的装饰器
使用装饰器实现登录的功能,定义检查登录的装饰器 check_login
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,如果没有登录则返回错误。
在第 6 行和第 7 行,检查请求中的参数 user 是否为 ‘zhangsan’,如果 user 等于 ‘zhangsan’,表示用户已经登录,则调用 original_function,否则返回 ‘请先登录’。
在第 4 行,使用 functools.wraps (original_function) 保留原始函数 original_function 的属性。
5.2 在视图函数中使用装饰器
创建文件 app.py:
from functools import wraps from flask import request, Flask 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' if __name__ == '__main__': app.run(debug=True)
程序有 2 个页面 /page1 和 /page2,只有登录的用户才能访问这两个页面。
函数 page1 被装饰了 2 次,它的原始功能是处理 /page1 的页面逻辑,被 @check_login 装饰后,具备了检查登录的功能,被 @app.route (’/page1’) 装饰后,绑定到路径为 /page1 的 URL,当访问 /page1 时,会访问 page1 函数。函数 page2 的功能类似。
登录后访问的页面:登录后即指url带user参数
5.3 在视图类中使用装饰器
创建文件 app.py:
from functools import wraps from flask import request, Flask,views 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=Page1.as_view('Page2')) if __name__ == '__main__': app.run(debug=True)
程序有 2 个页面 /page1 和 /page2,只有登录的用户才能访问这两个页面。
类 Page1 的原始功能是处理 /page1 的页面逻辑,在第 9 行,decorators = [check_login] 设定视图类的装饰器,当访问 /page1 时,首先执行检查登录,然后再执行原始的功能。
运行效果跟视图函数一致。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步