Flask CBV源码
参考:https://flask.palletsprojects.com/en/3.0.x/views/
# CBV的执行流程
1、请求来了,路由匹配成功--->执行ItemAPI.as_view('item')()--->view加括号执行
2、2 ItemAPI.as_view('item')执行结果:就是View中as_view方法中的闭包函数 view
def view(**kwargs: t.Any) -> ft.ResponseReturnValue:
# 使用了异步返回了 dispatch_request 方法
return current_app.ensure_sync(self.dispatch_request)(**kwargs)
3、view()--->执行self.dispatch_request()--->执行MethodView的dispatch_request
def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue:
meth = getattr(self, request.method.lower(), None)
if meth is None and request.method == "HEAD":
meth = getattr(self, "get", None)
return current_app.ensure_sync(meth)(**kwargs)
4、如果是get请求,就会执行视图类中的get方法
#2、endpoint 的使用
app.add_url_rule('/item', endpoint='xxx',view_func=ItemAPI.as_view('item'))
如果写了endpoint--->别名以它为准,如果不写以as_view中写的字符串为准
#逻辑:
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
### cbv中加装饰器
1 使用步骤:在类中加入类属性:
class ItemAPI(MethodView):
decorators = [装饰器,装饰器2]
def get(self):
# print(url_for('xxx'))
print(url_for('item'))
return 'get'
2
if cls.decorators:
for decorator in cls.decorators:
view = decorator(view)
'''
@装饰器
def view()
'''
整个cbv执行流程
# View的as_view
@classmethod
def as_view(cls, name, *class_args, **class_kwargs) :
def view(**kwargs):
return self.dispatch_request(**kwargs)
if cls.decorators: # 咱们的装饰器
for decorator in cls.decorators: #每次拿出一个装饰器,
view = decorator(view) # 装饰器语法糖干的事: 把被装饰的函数当参数传入到装饰器,返回结果赋值给被装饰的函数,一个个用装饰器包装view
view.__name__ = name
return view
# self.dispatch_request---》MethodView
def dispatch_request(self, **kwargs) :
# 取到request.method.lower()请求方式小写 ---》假设是get请求get
# meth是 cbv中 以get命名的方法,反射出来了
meth = getattr(self, request.method.lower(), None)
return meth(**kwargs) # 执行cbv中跟请求方式同名的方法
路由的其他写法
def register_api(app, model, name):
item = ItemAPI.as_view(f"{name}-item", model)
group = GroupAPI.as_view(f"{name}-group", model)
app.add_url_rule(f"/{name}/<int:id>", view_func=item) # get put delete
app.add_url_rule(f"/{name}/", view_func=group) #post get
register_api(app, User, "users")
register_api(app, Story, "stories")
模版
# flask使用了Jinja,flask提供了文档,也可以去Jinja官网看
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 跟之前一样
请求响应
flask:
requset:全局的,但是也是每个请求一个request,
response:新手三件套
# request 全局对象
request.method 请求的方法
request.args get请求提交的数据
request.form post请求提交的数据
request.values post和get提交的数据总和
request.cookies 客户端所带的cookie
request.headers 请求头
request.path 不带域名,请求路径
request.full_path 不带域名,带参数的请求路径
request.url 带域名带参数的请求路径
request.base_url 带域名请求路径
request.url_root 域名
request.host_url 域名
request.host 服务端地址
# 保存文件
request.files
obj = request.files['the_file_name']
obj.save('/var/www/uploads/' + secure_filename(f.filename))
# 响应 response--->四件套
-return '字符串'
-return render_template('index.html',name=lqz,age=19)
-return redirect(url_for(别名))/redirect("login")
-return jsonify(字典,列表)
# 往cookie中写数据--->四件套需要使用
obj=make_response('index')
obj.set_cookies() # 跟之前一样
# obj.headers[] # 往请求头中添加东西
session
# cookie 机制
# 设置
obj=make_response('index')
obj.set_cookies('name','lqz')
# 取
request.cookie.get('name')
# session机制
1 设置秘钥
2 写入session
session['username']='xxx'
3 取出session
username = session.get('username')
参考项目
https://toscode.mulanos.cn/pear-admin/pear-admin-flask
# 1 git clone https://toscode.mulanos.cn/pear-admin/pear-admin-flask
# 2 改配置文件
MYSQL_USERNAME = "root"
MYSQL_PASSWORD = "lqz123?"
MYSQL_HOST = "127.0.0.1"
MYSQL_PORT = 3306
MYSQL_DATABASE = "PearAdminFlask"
# 数据库的配置信息
# SQLALCHEMY_DATABASE_URI = 'sqlite:///../pear.db'
SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USERNAME}:{urlquote(MYSQL_PASSWORD)}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}?charset=utf8mb4"
# 3创建数据库 PearAdminFlask
# 4 执行初始化
flask db init
# 5 migrate.bat
# 6 flask admin init
# 7 启动
run.bat
# 8 改代码--->密码不判断