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'
posted @   Edmond辉仔  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示