Flask02--路由、模板、请求与响应、session、flash闪现、请求拓展(中间件)、蓝图
0 多个装饰器的执行顺序
# flask的路由基于装饰器----》根绝业务逻辑,以后还会在视图函数上再加装饰器
# 多个装饰器的执行顺序:
从上往下,依次执行
# 快速记忆:装饰器就是塑料袋一层层的包装,先执行外层,在内层
# eg:
登录认证装饰器,加在router下面,
先做路由匹配,匹配成功 再执行被auth包裹的视图函数
1 路由系统
# flask的路由是 基于装饰器的,但本质就是一个方法函数
本质是flask类的add_url_rule方法--->等同于django的path('/',index,name='index')
# eg:不用装饰器,而是函数方式注册路由
# @app.route(rule='/',methods=['GET'],endpoint='index') # index=app.route()(index)
def index():
return 'hello flask'
# 本质是
app.add_url_rule(rule='/',endpoint='index',view_func=index,methods=['GET'])
1.1 转换器
# 装换器形式:
@app.route('/index/<string:name>', endpoint='index', methods=['GET'])
# 默认转化器:跟django 2.x后的转换器一样
DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
1.2 路由系统的本质
# 1.route的源代码
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
# 2.route装饰器的实质
@app.route('/',methods=['GET','POST'],endpoint='n1')
def index():
pass
# @语法糖的作用:
index = app.route()(index)
---> decorator(index)
---> 本质就是 执行self.add_url_rule(),再返回index地址
# 3 路由可以写成函数形式:
app.add_url_rule(rule='/',endpoint='index',view_func=index,methods=['GET'])
# 4 endpoint如果不传,是None,也有个默认值(函数的名字, 通过函数.__name__) 了解
-如果使用了装饰器,一定要指定endpoint
-或装饰器要完全伪装:
from functionTools import wraps
@wraps(func)
1.3 app.add_url_rule参数
# @app.route和app.add_url_rule参数:
1.rule
# URL匹配规则
2.view_func
# 视图函数名称 内存地址
3.defaults = None
# 默认值, 当URL中无参数,而视图函数需要参数时,使用defaults = {'k': 'v'} 为函数提供参数
4.endpoint = None
# 名称,用于反向生成URL 即: url_for('名称') 获取到对应匹配的url
5.methods = None
# 允许的请求方式,如:["GET", "POST"]
6.strict_slashes = None
# 对URL最后的 / 符号是否严格要求
@app.route('/index', strict_slashes=False)
# 访问http://www.xx.com/index/ 或http://www.xx.com/index均可
@app.route('/index', strict_slashes=True)
# 仅访问http://www.xx.com/index
7.redirect_to = None,
# 重定向到指定地址
@app.route('/index/<int:nid>', redirect_to='/home/<nid>')
8.subdomain = None
# 子域名访问
1.4 支持正则(不用)
# 1 写类,继承BaseConverter
# 2 注册:app.url_map.converters['regex'] = RegexConverter
# 3 使用:@app.route('/index/<regex("\d+"):nid>') 正则表达式会当作第二个参数传递到类中
from flask import Flask, views, url_for
from werkzeug.routing import BaseConverter
app = Flask(import_name=__name__)
class RegexConverter(BaseConverter):
"""
自定义URL匹配正则表达式
"""
def __init__(self, map, regex):
super(RegexConverter, self).__init__(map)
self.regex = regex
def to_python(self, value):
"""
路由匹配时,匹配成功后传递给视图函数中参数的值
"""
return int(value)
def to_url(self, value):
"""
使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
"""
val = super(RegexConverter, self).to_url(value)
return val
# 添加到flask中
app.url_map.converters['regex'] = RegexConverter
@app.route('/index/<regex("\d+"):nid>')
def index(nid):
print(url_for('index', nid='888'))
return 'Index'
if __name__ == '__main__':
app.run()
1.5 CBV源码分析(跟djagno没有区别)
from flask import Flask, url_for
from flask.views import MethodView
app = Flask(__name__)
app.debug = True # 热更新---->不停机更新
# 1 写一个类,继承MethodView
class LoginView(MethodView):
methods = ['GET', 'POST']
# 添加装饰器
decorators = [auth1,auth2]
def get(self):
return 'get --login'
def post(self):
return 'post---login'
# 2 配置路由,LoginView.as_view()但是必须带一个参数,参数是这个地址的别名
app.add_url_rule('/login', view_func=LoginView.as_view('login')) # name=endpoint
if __name__ == '__main__':
app.run()
2 模板语法
# 完全兼容DTL,比DTL强大一些,extends,include模板继承等也一模一样
# 区别:
1.针对标签的模板,flask后端使用Markup('标签字符串') 进行转义
Markup等价django的mark_safe
2.函数等可调用对象,可直接加括号调用,并支持传参
3 请求与响应
# 请求对象 是全局的request,需要导入使用
from flask import request
##### request对象属性和方法
request.method # 请求方法
request.args # get请求提交的数据
request.form # post请求提交的数据
request.values # post和get提交的数据总和(一般不用)
request.cookies # 客户端所带的cookie
request.headers # 请求头
http://127.0.0.1:5000/test_if?name=lqz&age=10
request.path # 不带域名,请求路径
eg: ---> /test_if
request.full_path # 不带域名,带参数的请求路径
eg: ---> /test_if?name=lqz&age=10
request.url # 带域名带参数的请求路径-->最完整的路径
eg: ---> http://127.0.0.1:5000/test_if?name=lqz&age=10
request.base_url # 带域名请求路径 不带参数
eg: ---> http://127.0.0.1:5000/test_if
request.url_root # 域名 http://127.0.0.1:5000/
request.host_url # 域名 http://127.0.0.1:5000/
request.host # 127.0.0.1:500
request.files # 客户端上传的文件
# eg: obj = request.files['the_file_name'] # 文件对象
request.url_rule # 获取视图的 url匹配规则
# eg: "/tag/edit/<int:id>/"
##### response对象
# 新手四件套
return "字符串"
return render_template('html模板路径',**{})
return redirect('/index.html')
return jsonify({'k1':'v1'})
# 响应对象-额外处理:cookie、请求头等操作
from flask import make_response
需要重新make_response('四件套内容') 制作成响应对象
response = make_response(render_template('index.html'))
# response是flask.wrappers.Response类型
# 响应对象-删除cookie
response.delete_cookie('key')
# 响应对象-设置cookie
response.set_cookie('key', 'value')
# 响应对象-添加响应头
response.headers['X-Something'] = 'A value'
return response
4 session
# session 对象
允许你在不同请求间存储特定用户的信息
是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话
# 设置密钥
app.secret_key = 'dddddddddd'
# 通过全局的session
from flask import session
# 设置值
session['key']=value
-回到前端的是token,所以没有在服务端存东西
-jwt原理很像
# 取值
session['key']
# 删除值
del session['key']
# 注:不用管不同的用户,统一都用全局session取,不会乱
# 实现原理: 等同于django中的 Session中间件 SessionMiddleware
-# 设置session session['key']=value
请求响应时 ---> 在请求走的时候把session中的值,加密序列化,放到cookie中,并返回给前端
-# 获取session session['key']
前端再一次请求时 (会带着cookie) ---> 从cookie中取值,反解出数据,生成session对象,后端才能获取使用
# 部分源码解读 app.session_interface 是 SecureCookieSessionInterface对象
SecureCookieSessionInterface ---> 负责干上面那俩事
-get_signing_serializer: 加密session 并序列化 类似于JWT
-save_session: 走的时候
-open_session: 带着cookie来的时候
5 flash 闪现
# flash n. 闪现
# 前提:
存放值,都是同一个浏览器,才能获取 对应存放的数据
# 作用:
把一些数据放在某个位置,下次要用的时候,直接取出来,下次请求就不能获取了
核心:可以跨请求 获取数据
# django也有类似的东西 ---> message 这个中间件app
# 设置值
flash('一坨大便')
# 分类设值
flash('一个包子',category='bz')
flash('一个大便',category='db')
flash('又一个大便',category='db')
# 取值 当前视图请求可以一直获取,但在另一个视图函数中(其他请求) 再取就没了
res = get_flashed_messages()
# 分类取值
res = get_flashed_messages(category_filter=['db'])
# flash数据存放的位置
是放在session中 (存放在前端的cookie中) 等同于 session[ss]='sdsd'
# 应用场景:
在之前的请求中有些数据,需要带到下次请求中看,就可以使用闪现
# eg: 假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息
from flask import Flask, url_for, redirect, request, flash, get_flashed_messages
app = Flask(__name__)
app.secret_key = 'dddddddddd'
@app.route('/')
def index():
flash('出错了')
url = url_for('test')
return redirect(url)
@app.route('/test/', methods=['GET', 'POST'])
def test():
error = get_flashed_messages()
print(error)
return error + ' ok'
if __name__ == '__main__':
app.run()
6 请求扩展
# 类似于django的中间件,在请求来之前 和响应走之后,执行一些方法
# 总结
1 重点掌握before_request和after_request,
2 注意有多个的情况,执行顺序
3 before_request请求拦截后 返回response对象,其他所有的after_request也都会执行
6.1 before_request
类比django中间件中的process_request,在请求收到之前 绑定一个函数做一些事情
# 基于它做用户登录认证
@app.before_request
def process_request(*args,**kwargs):
if request.path == '/login':
return None
user = session.get('user_info')
if user:
return None
return redirect('/login')
# before_request
1.没有参数
2.返回值:
None # 进入下一个中间件,执行顺序跟 django一样,从上往下
响应对象 # 请求就会直接返回 不会走后面的视图函数
6.2 after_request
类比django中间件中的process_response,每一个请求之后 绑定一个函数,如果请求没有异常
@app.after_request
def process_response1(response):
print('process_response1 走了')
return response
# after_request
1.有参数 response
2.返回值: 必须返回 response对象 不然会报错
response # 进入下一个中间件,执行顺序跟 django一样,从下往上
6.3 before_first_request
项目启动后,第一次请求时触发,跟浏览器无关
@app.before_first_request
def first():
pass
# 场景: 内部本质是修改布尔类型的变量
常用来 做初始化
6.4 teardown_request
每一个请求之后 绑定一个函数,即使遇到了异常,也会触发执行
@app.teardown_request
def ter(e):
pass
# 注
app.debug = False # 才触发执行 因为调试模式下,异常会展示到前端浏览器
# 场景:
常用来 记录日志
6.5 errorhandler
传入状态码,若符合状态码时,就会触发执行
@app.errorhandler(404)
def error_404(arg):
return "404错误了"
# @app.errorhandler(404) 参数为状态码,若符合状态码时,就会执行
路径不存在时 : 404
服务器内部错误 : 500
# 场景:
请求路径错误--404页面
后端内部错误--500页面
6.6 template_global
标签 类似于 django的自定义标签
@app.template_global()
def sb(a1, a2):
return a1 + a2
# {{sb(1,2)}}
6.7 template_filter
过滤器 类似于 django的自定义过滤器
@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
# {{ 1|db(2,3)}}
7 蓝图
# blueprint 蓝图
# 作用:
对程序进行目录结构的划分,避免循环导入
不使用蓝图划分目录也可以,但是会出现循环导入
# 使用蓝图:
1 创建蓝图对象
user = Blueprint('user', __name__, template_folder='templates', static_folder='static')
# 给当前蓝图 指定 静态和模板文件 向上查找,当前找不到,会找总templates
2 使用蓝图对象 注册路由
@user.route('/test') # 以后路由都可以使用蓝图对象
def login():
return 'user test'
3 注册蓝图对象
app.register_blueprint(user,url_prefix='/user')
# 把所有蓝图在app中注册一下,可以指定前缀 表示在该蓝图下所有url都加前缀
# 注:
1.url_prefix是访问路由的前缀,在生成蓝图对象或者注册蓝图时添加都行
2.以后使用,都用蓝图对象作为原来的app(Flask对象)
3.蓝图对象,可以使用路由,也有请求拓展(只针对当前的蓝图有效)
# 自行构建划分目录:
# 小型项目: 应用都在views
flask_test
-flask_test
-__init__.py
-static
-templates
-views
-order.py
-user.py
-manage.py 或 run.py
# 大型项目: 模拟出django中 app的感觉
flask_test
-flask_test
-__init__.py
-admin
-__init__.py
-static
-templates
-views.py
-web
-__init__.py # 写蓝图的创建
-static
-templates
-views.py # 写蓝图注册路由 以及业务逻辑
-manage.py 或 run.py
manage.py
from flask_test import app
if __name__ == '__main__':
app.run()
flask_test/init.py
from flask import Flask
# 注册flask 的app
app = Flask(__name__)
# 导入下应用 好执行应用的代码
from .views import user
from .views import order
# 注册蓝图对象
app.register_blueprint(user.user)
app.register_blueprint(order.order)
user.py
from flask import Blueprint
# 创建蓝图对象
user = Blueprint('user', __name__, url_prefix='/user')
# 蓝图对象注册路由
@user.route('/test')
def login():
return 'user test'
分类:
Flask
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本