flask之cbv、模版
一、CBV介绍
1、class-based views, CBVs
通常使用函数视图(function-based views, FBVs)来定义路由和处理逻辑。不过,Flask 也支持基于类的视图(class-based views, CBVs),这可以帮助在需要共享逻辑或管理复杂视图结构时组织代码。
基于类的视图 CBV 的特点
- 组织性:CBV 方式可以更好地组织和重用代码,尤其适用于复杂的视图逻辑。
- 可继承性:可以通过类继承的方式实现逻辑的共享和复用。
- 封装性:通过类的方法封装不同的 HTTP 请求方法(如 GET、POST、PUT 等)逻辑。
2、类要继承MethodView
CBV 的基本方式是通过继承 flask.views.MethodView
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | from flask import Flask, request, jsonify, url_for from flask.views import MethodView app = Flask(__name__) class MyView(MethodView): def get( self ): return jsonify({ "message" : "This is a GET request" }) def post( self ): data = request.get_json() print (url_for( "my_view" )) return jsonify({ "message" : "This is a POST request" , "data" : data}) # 注册路由,绑定视图类 app.add_url_rule( '/myview' , view_func = MyView.as_view( 'my_view' )) if __name__ = = '__main__' : app.run(debug = True ) |
补充:
指定方法名称:
在基于类的视图中,HTTP 方法名 get
, post
, delete
应该直接作为方法名。Flask
自动根据请求的 HTTP 方法调用相应的类方法。因此,需要定义 get
, post
, delete
方法,而不是 mesg1
, mesg2
等自定义方法名称。
也可以显式声明 methods
属性, 如果显式声明了,不在声明中的方法将不被允许
1 2 3 4 5 6 7 8 9 10 | class MyView(MethodView): methods = [ 'get' , 'post' ] def get( self ): return jsonify({ "message" : "This is a GET request" }) def post( self ): data = request.get_json() print (url_for( "my_view" )) return jsonify({ "message" : "This is a POST request" , "data" : data}) |
3、路由的别名
view_func=MyView.as_view
1 2 3 4 | def post( self ): data = request.get_json() print (url_for( "my_view" )) return jsonify({ "message" : "This is a POST request" , "data" : data}) |
通过url_for反向解析路由,MyView.as_view 括号中的内容my_view 是myview的别名
即myview怎么修改name,都可以通过别名my_view 去解析到
4、cbv加装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # 定义一个简单的认证装饰器 def api_key_required(f): @wraps (f) def decorated_function( * args, * * kwargs): if request.headers.get( "API-Key" ) ! = "my-secret-key" : return jsonify({ "error" : "Unauthorized" }), 401 return f( * args, * * kwargs) return decorated_function # 全局装饰器,decorators = [xxx] class MyView(MethodView): decorators = [api_key_required] def get( self ): return jsonify({ "message" : "This is a GET request" }) def post( self ): data = request.get_json() return jsonify({ "message" : "This is a POST request" , "data" : data}) # 局部装饰 写在类中方法上 class MyView(MethodView): def get( self ): return jsonify({ "message" : "This is a GET request" }) @api_key_required def post( self ): data = request.get_json() return jsonify({ "message" : "This is a POST request" , "data" : data}) |
5、cbv 源码分析
MethodView继承了View,View中有as_view方法---> 本质是执行了dispath_request---->View没有写 dipatch(空的内容)---> MethodView写了所以,视图类必须要继承MethodView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 1 请求来了,路由匹配成功 - - - 》执行ItemAPI.as_view( 'item' )() - - - >view加括号执行 2 ItemAPI.as_view( 'item' )执行结果:就是View中as_view方法中的闭包函数 view 3 view() - - - >执行 self .dispatch_request() - - - 》执行MethodView的dispatch_request def dispatch_request( self , * * kwargs): meth = getattr ( self , request.method.lower(), None ) return meth( * * kwargs) 4 如果是get请求,就会执行视图类中的get方法 class View: @classmethod def as_view() def view(): self .dispatch_request() return view |
6、endpoint 的使用
1 | app.add_url_rule( '/item' , endpoint = 'xxx' ,view_func = ItemAPI.as_view( 'item' )) |
如果写了endpoint---> 别名以它为准,如果不写以 as_view的参数为准
## 逻辑:
1 2 3 4 5 6 7 8 | 1 app.add_url_rule( '/item' ,endpoint = 'xxx' , view_func = ItemAPI.as_view( 'item' )) 2 endpoint = _endpoint_from_view_func(view_func) 如果endpoint没传,就会走这句 view_func 是 ItemAPI.as_view( 'item' ) 它就是 view 3 _endpoint_from_view_func(view_func) - - - 》返回了传入的函数的名字 return view_func.__name__ 4 如果上面传入了ItemAPI.as_view( 'item' ),它的函数名就是view - - - 》endpoint就是view |
## 总结:
endpoint如果不传,会以视图函数的函数名作为endpoint
-fbv:如果不写endpoint,会以函数名作为endpoint,但是如果多个视图函数加了同一个装饰器,又没有指定endpoint,就会出错了
-cbv:调用as_view一定要传入一个字符串---》如果endpoint没写,endpoint就是传入的这个字符串,如果写了,这个字符串没用
如果传了,直接以endpoint传入的作为endpoint
二、模版(前端使用的模版)
1、flask使用了Jinja模版
flask提供了文档,也可以去Jinja官网看
1 2 3 4 5 6 7 8 9 10 | https: / / flask.palletsprojects.com / en / 3.0 .x / https: / / jinja.palletsprojects.com / en / 3.1 .x / # 总结:之前学过dtl - {{变量 / 简单表达式 / 函数}} - { % if / for % } { % endif % } { % endfor % } - 比dtl强大 ,Jinja中可以加括号 - 字典取值,列表取值跟python语言一样,之前dtl 通过 .取值 - 过滤器,标签 - extends,include 跟之前一样 |