当前位置:网站首页>flask——请求、响应、请求扩展、session、闪现、蓝图、g对象、flask-session

flask——请求、响应、请求扩展、session、闪现、蓝图、g对象、flask-session

2022-08-09 23:39:00 山上有个车

系列文章目录

第一章 介绍、安装、快速使用、配置文件、路由系统、视图

第二章 请求、响应、请求扩展、session、闪现、蓝图、g对象、flask-session



一、请求

方法作用
request.method请求方式
request.argsget 请求参数
request.formpost提交的数据
request.valuesget,post提交的数据总和
request.cookiescookies
request.headers请求头
request.path路由路径,例如: /login
request.full_path路由路径以及路径中携带的参数,例如: /login?name=kdq&age=88
request.script_root当前url路径的上一级路径
request.url完整的url,例如: http://127.0.0.1:5000/login?name=kdq&age=88
request.base_url部分的url(不包括路径参数),例如: http://127.0.0.1:5000/login
request.url_root当前url的路径的上一级完整路径(域名+端口),例如: http://127.0.0.1:5000/
request.host_url域名+端口,例如: http://127.0.0.1:5000/
request.host不带http的域名+端口,例如: 127.0.0.1:5000
request.files.get(‘file’)获取文件

二、响应

1.make_response

向浏览器中写入cookie,返回方法可以使用make_response包裹一下变成响应对象

res=make_response(render_template('home.html'))
res.set_cookie('name','bbc')

2.向浏览器中写响应头

res.headers['X-Something'] = 'A value'

三、请求扩展

flask的请求扩展是使用装饰器,可以完成请求传入、请求传出、抛异常、资源找不到等等情况的,执行该装饰器装饰的函数。

from flask import Flask, redirect, render_template, jsonify

app = Flask(__name__)


@app.route('/', methods=['GET'])
def index():

    return render_template('home.html')


@app.before_first_request  # 项目第一次运行时执行一次该函数(flask2.3已弃用该装饰器)
def beforefr():
    print('before_first_request')  # 此处无法return返回响应


@app.before_request  # 请求传入之前执行
def beforer():
    print('before_request')
    # return 'asdd' 替换request并终止request的运行流程直接执行response操作
    # return render_template('home.html') 替换request并终止request的运行流程直接执行response操作
    # return redirect('/login') 替换request并终止request的运行流程直接执行response操作
    # return jsonify('name', 'ool') 替换request并终止request的运行流程直接执行response操作
    return None  # 继续执行request的运行流程


@app.after_request  # 请求传入之后执行
def afterr(response):  # 参数为请求之后返回的响应
    print('after_request')
    # return 'asdd' 替换request并终止request的运行流程直接执行response操作
    # return render_template('home.html') 替换request并终止request的运行流程直接执行response操作
    # return redirect('/login') 替换request并终止request的运行流程直接执行response操作
    # return jsonify('name', 'ool') 替换request并终止request的运行流程直接执行response操作
    return response  # 继续执行request的运行流程


@app.teardown_request  # 无论程序是否出异常,都会执行 app.debug=False模式才行
def teardownr(e):  # 参数为错误信息
    print('-------------')
    print(e)  # 此处无法return返回响应
    print('-------------')


@app.errorhandler(500)  # 触发对应错误状态时执行(错误状态自行设置)
def errorh(arg):
    print(arg)  # 对错误信息的处理
    return jsonify({
    'code': 888, 'msg': '请联系系统管理员'})


@app.template_global()  # 标签
def sum(a, b):
    return a + b


@app.template_filter()  # 过滤器
def db(a1, a2, a3):
    return (a1 - a2) * a3


if __name__ == '__main__':
    app.run()

过滤器和标签的使用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{
   {sum(99,1)}} 标签使用
<hr>
{
   {5|db(3,2)}} flask的模板语法中过滤器可以带n个参数第一个固定在|左侧
</body>
</html>

执行顺序:
1 @app.before_first_request 项目启动时执行一次
2 @app.before_request 请求传入之前执行所有的该装饰器(多个情况从代码上到下执行,如果有返回值直接跳到response执行流程)
3 @app.after_request 请求结束,传递响应时执行(多个情况从代码上到下执行,如果有返回值直接将response返回给客户端)
4 @app.errorhandler 监听异常(可进行异常处理、记日志等)
5 @app.teardown_request 只能使用异常信息,无法对异常进行处理(无法使用return)


四、session

1.session源码分析

通过app.session_interface

找到了

session_interface: SessionInterface = SecureCookieSessionInterface()

在SecureCookieSessionInterface类对象中找到了俩个方法
其中open_session是读取session用的
save_session是写入session用的

    def open_session(
        self, app: "Flask", request: "Request"
    ) -> t.Optional[SecureCookieSession]:
        s = self.get_signing_serializer(app)
        if s is None: # 判断secret_key是否为None
            return None
        val = request.cookies.get(self.get_cookie_name(app))
        if not val: # 判断session是否存在于请求中
            return self.session_class()
        max_age = int(app.permanent_session_lifetime.total_seconds()) # session过期时间默认为31天
        try:
            data = s.loads(val, max_age=max_age) 
            return self.session_class(data)
        except BadSignature:
            return self.session_class()

    def save_session(
        self, app: "Flask", session: SessionMixin, response: "Response"
    ) -> None:
        name = self.get_cookie_name(app)
        domain = self.get_cookie_domain(app)
        path = self.get_cookie_path(app)
        secure = self.get_cookie_secure(app)
        samesite = self.get_cookie_samesite(app)
        httponly = self.get_cookie_httponly(app)

        if not session: # session是否为空
            if session.modified: # 如果session发生改动
                response.delete_cookie( # 删除session
                    name,
                    domain=domain,
                    path=path,
                    secure=secure,
                    samesite=samesite,
                    httponly=httponly,
                )

            return

        if session.accessed:
            response.vary.add("Cookie")

        if not self.should_set_cookie(app, session):
            return

        expires = self.get_expiration_time(app, session) # session的生成
        val = self.get_signing_serializer(app).dumps(dict(session))  # type: ignore
        response.set_cookie( # 将session放入response中
            name,
            val,  # type: ignore
            expires=expires,
            httponly=httponly,
            domain=domain,
            path=path,
            secure=secure,
            samesite=samesite,
        )

2.session的使用

from flask import Flask, make_response, session, request

app = Flask(__name__)
app.debug = True
app.secret_key = 'asd$%@#_sdasfrt'

@app.route('/set_session')
def set_session():
    # 生成session方式一 该方式存放的session是明文
    # res = make_response('session生成')
    # res.set_cookie('name', 'bbc')
    # return res

    # 生成session方式二 该方式需要配置secret_key
    session['name'] = 'bbc'
    return 'session生成'

@app.route('/get_session')
def get_session():
    # 获取session方式一
    # name = request.cookies.get('name')
    # return 'session,name:%s'%name

    # 获取session方式二
    name = session['name']

    # 删除session
    # session.pop('name')
    return 'session,name:%s' % name

if __name__ == '__main__':
    app.run()

五、闪现(flash)

假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息

本质其实就是在a页面,把信息放到了session,在b页面把信息取出来

在一次请求中,把一些数据放在闪现中,下次请求就可以从闪现中取出来,取一次就没了(使用分类也是这样)

不使用分类示例:

from flask import Flask, flash, get_flashed_messages, session, render_template, redirect

app = Flask(__name__)

app.debug = True
app.secret_key = 'asd#$)*)[email protected]#55'

@app.route('/')
def home():
    try:
        b = 5 / 0
    except:
        flash('主页出错了') 
        return redirect('/error')
    return render_template('home.html')

@app.route('/error')
def errorhtml():
    return render_template('error.html', error=get_flashed_messages())

if __name__ == '__main__':
    app.run()

使用分类示例:

from flask import Flask, flash, get_flashed_messages, session, render_template, redirect

app = Flask(__name__)

app.debug = True
app.secret_key = 'asd#$)*)[email protected]#55'

@app.route('/')
def home():
    try:
        b = 5 / 0
    except:
        flash('主页出错了', category='server')
        flash('计算出错了', category='msg')
    return render_template('home.html')

@app.route('/errormsg')
def errormsg():
    return render_template('error.html', error=get_flashed_messages(category_filter='msg'))

@app.route('/errorserver')
def errorserver():
    return render_template('error.html', error=get_flashed_messages(category_filter='server'))

if __name__ == '__main__':
    app.run()

六、蓝图(Blue_print)

蓝图是对目录的划分,当我们的项目越来越大时,如果所有代码都放在一个py中会越来越臃肿,代码的可读性与维护性就会降低,这个时候划分目录可以让项目便于维护和开发。

不使用蓝图进行目录划分:

在这里插入图片描述

home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>主页</h1>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>登录</h1>
<from>
    <p>用户名 <input type="text"></p>
    <p>密码 <input type="password"></p>
    <button type="submit">登录</button>
</from>
</body>
</html>

views/_ _ init _ _.py

from flask import Flask, render_template

app = Flask(__name__, template_folder='../templates')
app.debug = True
app.secret_key = '123%#jsd()%GGE34'

from . import home
from . import login

home.py

from Blue_print.views import app, render_template

@app.route('/')
def home():
    return render_template('home.html')

login.py

from Blue_print.views import app, render_template

@app.route('/login')
def login():
    return render_template('login.html')

app.py

from Blue_print.views import app

if __name__ == '__main__':
    app.run()

不使用蓝图划分目录容易出现循环导入问题

1.蓝图的使用步骤:

1 实例化得到蓝图对象 ---可以传一些参数:account = Blueprint('account', __name__,templates,static)
2 把蓝图对象在app中注册---》app.register_blueprint(account,制定前缀)
3 使用蓝图对象,注册路由
4 蓝图有自己的请求扩展--》app对象总的请求扩展,每个蓝图有自己的请求扩展

使用蓝图来做目录划分 主要目的是使用蓝图对象,取代app对象

2.小项目蓝图

-小型项目:目录结构如下,只有一个app的项目
        -flask_pro               #项目名
            -pro_flask          # 文件夹
                -__init__.py    # 包的init文件
                -static          #静态文件
                	-code.png
                -templates       #模板文件
                	-index.html
                -views           #视图函数写在里面
                    -account.py    #订单相关视图函数
                    -user.py     #用户相关视图函数
                    -blog.py     #博客相关视图函数
             -manage.py          # 项目的启动文件

在这里插入图片描述

blog.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>blog</h1>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="">
  <p>用户名:<input type="text"></p>
</form>
<img src="/static/code.png" alt="">
</body>
</html>

account.py


from flask import Blueprint
from flask import render_template
# 实例化得到蓝图对象
account = Blueprint('account', __name__)


@account.route('/login.html', methods=['GET', "POST"])
def login():
    return render_template('login.html')

blog.py

from flask import Blueprint, render_template,request

blog = Blueprint('blog', __name__)

@blog.route('/get_blog')
def get_blog():
    print(request.path)
    return render_template('blog.html')

pro_flask/ _ _ init_ _.py


from flask import Flask

app = Flask(__name__,template_folder='templates',static_folder='statics',static_url_path='/static')

from .views.account import account
from .views.blog import blog

# 注册3个蓝图,把他们注册进app中
app.register_blueprint(account)
app.register_blueprint(blog)

manage.py 名字可以自定义

from pro_flask import app


if __name__ == '__main__':
    app.run()

3.大型项目蓝图

pro_flask   # 项目名
    -pro_flask #包名
        -admin #admin app的名字
            -static #app自己的静态文件
            -templates #app自己的模板文件
            -__init__.py #包的init
            -views.py   #app自己的视图函数
        -web  #web app的名字
            -static  #app自己的静态文件
            -templates #app自己的模板文件
            -__init__.py #包的init
            -views.py  #app自己的视图函数
        -__init__.py
    -run.py # 启动文件

在这里插入图片描述

admin.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>我是admin</h1>
<img src="/admin/static/mv.jpg" alt="">
</body>
</html>

admin/_ _ init_ _.py


from flask import Blueprint

# 第一步:初始化蓝图
admin = Blueprint(
    'admin',
    __name__,
    template_folder='templates',  # 指定该蓝图对象自己的模板文件路径
    static_folder='static'       # 指定该蓝图对象自己的静态文件路径
)


from . import views

admin/views.py

from . import admin
from flask import render_template


@admin.before_request
def before():
    print('admin 的 before')


# 第三步:使用蓝图注册路由
@admin.route('/index')
def index():
    return render_template('admin.html')

web/_ _ init_ _.py


from flask import Blueprint

web = Blueprint(
    'web',
    __name__,
    template_folder='templates',
    static_folder='static'
)
from . import views

web/views.py

from . import web

@web.route('/index')
def index():
    return 'Web.Index'

pro_flask/_ _ init_ _.py


from flask import Flask


from .admin import admin
from .web import web

app = Flask(__name__)
app.debug = True

# 第二步:在app中注册蓝图
app.register_blueprint(admin, url_prefix='/admin') # url_prefix='/admin' 访问这个app的前缀,等同于include
app.register_blueprint(web)

run.py

from pro_flask import app

if __name__ == '__main__':
    app.run()

七、g对象

flask 中有个 g 对象,在一次请求中,可以赋值,取值 。当次请求中的全局对象,在一次请求中写入值,后续就可以取出来
如果使用request存值取值会发生request中原有的值被覆盖掉,所以为了防止request中原有的值被覆盖掉,flask提供了g对象

g和session的区别:
g只对当次请求有效
session对该用户的所有请求都有效

g对象的使用方式:

g.key = value # 存值
g.name # 取值

示例代码

from flask import Flask, g, request,session

app = Flask(__name__)
app.debug=True


@app.before_request
def before():
    print(type(g))  # werkzeug.local.LocalProxy 代理模式
    print(type(session))
    print(type(request))
    if request.path == '/':
        # request.method='lqz'
        g.name = 'lqz'  # 放到g对象中
    else:
        # request.name = 'pyy'
        g.name = 'pyy'
        
def add(a,b):
    print(g.name)
    # print('-----', request.name)

@app.route('/')
def index():
    print(g.name)
    # print('-----',request.name)
    # add(1,2)
    return 'hello'


@app.route('/home')
def home():
    print(g.name)
    return 'hello'


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

八、flask-session

flask的session默认以cookie的形式放到浏览中,我们想把session,放到服务端保存(redis、mysql等)

只需要写一个类,编写open_session和save_session方法

使用flask-session

#使用flask-session:方式一:
from flask_session import RedisSessionInterface
app.session_interface=RedisSessionInterface(redis=None,key_prefix='luffy_') 
# key_prefix配置key的前缀
# redis配置redis
#方式二:通用方案
from redis import Redis
from flask_session import Session
#### 以下三行会放在配置文件中
app.config['SESSION_TYPE'] = 'redis' 
app.config['SESSION_KEY_PREFIX'] = 'luffy' # 配置key的前缀
app.config['SESSION_REDIS'] = Redis(host='127.0.0.1',port='6379')
####
Session(app)  #常见这种写法
原网站

版权声明
本文为[山上有个车]所创,转载请带上原文链接,感谢
https://blog.csdn.net/kdq18486588014/article/details/126235710