session源码
'''
1 app.session_interface 默认是某个类的对象,以后全局对象 session,就是SecureCookieSessionInterface()的对象
2 请求来了,会执行这个对象的: open_session方法
3 请求走了,会执行这个对象的:save_session方法
4 找出上面讲的--》读源码--》
app.run()---->run_simple(地址, 端口, self可调用对象)--->self 是谁?就是 app
请求来了,就会执行 self可调用对象()--->app()---->对象加括号---》触发---》类的__call__
请求来了,就会执行flask类的 __call__--->self.wsgi_app(environ, start_response)
def wsgi_app(self, environ: dict, start_response: t.Callable) -> t.Any:
ctx = self.request_context(environ)
try:
try:
ctx.push()
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if "werkzeug.debug.preserve_context" in environ:
environ["werkzeug.debug.preserve_context"](_cv_app.get())
environ["werkzeug.debug.preserve_context"](_cv_request.get())
if error is not None and self.should_ignore_error(error):
error = None
ctx.pop(error)
# 5 ctx.push()--->有如下代码
if self.session is None: # 请求刚来,是空的
#session_interface 就是SecureCookieSessionInterface类的对象
self.session = session_interface.open_session(self.app, self.request)
if self.session is None:
self.session = session_interface.make_null_session(self.app)
#6 SecureCookieSessionInterface类的open_session
from flask.sessions import SecureCookieSessionInterface
open_session步骤:
1 会去cookie中取出session对应的 三段式的字符串
2 解密,校验签名---》把这个数据--》放到 session对象中
save_session步骤:
1 从session取出数据
2 加密,签名---放到cookie中
3 返回给前端
'''
save_session
'''
1 视图函数中,咱们 session[name]=lqz
2 请求走了,会触发save_session
3 触发save_session时:
把session中的数据,加密签名得到三段字符串
放到cookie中,放到了浏览器中
'''
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 session.accessed:
response.vary.add("Cookie")
if not session:
if session.modified:
response.delete_cookie(
name,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
httponly=httponly,
)
response.vary.add("Cookie")
return
if not self.should_set_cookie(app, session):
return
expires = self.get_expiration_time(app, session)
val = self.get_signing_serializer(app).dumps(dict(session))
response.set_cookie(
name,
val,
expires=expires,
httponly=httponly,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
)
response.vary.add("Cookie")
open_session
'''
1 请求来了,request中带着cookie(也有可能没有)
2 根据 session这个key,取出value,如果有,就是 我们当时生成的三段
3 字典=s.loads(value) 把内容验签,解密出来,转成了字典
4 把这个字典转到 session对象中
5 以后视图函数中 session[name] 就能取到当时你放的name
'''
def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None:
s = self.get_signing_serializer(app)
if s is None:
return None
val = request.cookies.get(self.get_cookie_name(app))
if not val:
return self.session_class()
max_age = int(app.permanent_session_lifetime.total_seconds())
try:
data = s.loads(val, max_age=max_age)
return self.session_class(data)
except BadSignature:
return self.session_class()
django session的控制:
from django.contrib.sessions.middleware import SessionMiddleware
闪现
flash(s, category='xxx')
flash('xxx', category='yyy')
err = get_flashed_messages(category_filter=['xxx'])[0]
1 设置flash,可以按分类设置
2 去flash,在当前请求中,可以取出多次,都是在的
3 一旦有请求取出,再去别的的请求中取,就没了,无论有没有分类,都没了
请求扩展
from flask import Flask, request, render_template, jsonify
app = Flask(__name__)
app.debug = True
@app.before_request
def before():
return "我来了"
@app.route("/")
def index():
return "xxx"
@app.after_request
def after(response):
print("我走了")
return response
@app.teardown_request
def error(exc):
print(exc)
print("teardown_request")
@app.route("/")
def index():
raise "我出错了"
return "index"
@app.errorhandler(404)
def error(exc):
print(exc)
return render_template("login.html")
@app.route("/")
def index():
return "index"
@app.template_global()
def sb(a1, a2):
return a1 + a2
@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
蓝图
Flsk_one
src
__init__.py
views.py
static
templates
main.py
__init__.py:
from flask import Flask
from src.views import bp_home
app = Flask(__name__)
app.register_blueprint(bp_home)
views.py:
from flask import Blueprint
bp_home = Blueprint("home", __name__)
@bp_home.route("/")
def index():
return "index"
main.py:
from src import app
if __name__ == '__main__':
app.run()
big_blueprint
-src
-admin
-static
-1.jpg
-templates
-admin_home.html
-__init__.py
-models.py
-views.py
-home
-order
-__init__.py
-settings.py
-manage.py
flask-session
之前的flask的session加密后放到了cookie中,如果想把session放到Redis中该如何去做?
借助于第三方的flask-session的模块:pip3 install flask-session
from flask import Flask, session
from flask_session import RedisSessionInterface
import redis
app = Flask(__name__)
app.secret_key = "asdjkadjksdskdjs"
conn = redis.Redis(host="127.0.0.1", port="6379")
app.session_interface = RedisSessionInterface(conn, "session")
def index():
session["name"] = "yang"
return "index"
app.add_url_rule("/index", view_func=index)
from flask_session import Session
from redis import Redis
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = Redis(host='127.0.0.1', port='6379')
Session(app)
- session的前缀如果不传,默认:config.setdefault('SESSION_KEY_PREFIX', 'session:')
- session的key理应该是 uuid,如果还是三段式-->之前浏览器器中存在了
数据库连接池
flask使用pymysql
from flask import Flask, jsonify
import pymysql
from pymysql.cursors import DictCursor
app = Flask(__name__)
app.debug = True
@app.route("/")
def index():
coon = pymysql.connect(
user="root",
password="020501",
host="127.0.0.1",
database="pearadminflask",
port=3306
)
cursor = coon.cursor(DictCursor)
sql = "select id,name,url from article limit 10"
cursor.execute(sql)
res = cursor.fetchall()
return jsonify({"code": 200, "msg": "成功", "result": res})
并发问题:conn和cursor 要做成单例,还是每个视图函数一个?
-如果用单例,数据会错乱
-咱们需要,每个视图函数,拿一个连接--->如果并发数过多,mysql连接数就很多--->使用连接池解决
-数据库连接池
-创建一个全局的池
-每次进入视图函数,从池中取一个连接使用,使用完放回到池中,只要控制池的大小,就能控制mysql连接数
-1 安装 pip3 install dbutils
-2 使用:实例化得到一个池对象--->池是单例
from dbutils.pooled_db import PooledDB
import pymysql
POOL = PooledDB(
creator=pymysql,
maxconnections=6,
mincached=2,
maxcached=5,
maxshared=3,
blocking=True,
maxusage=None,
setsession=[],
ping=0,
host='127.0.0.1',
port=3306,
user='root',
password='020501',
database='pearadminflask',
charset='utf8'
)
from flask import Flask, jsonify
from mysql_pool import POOL
app = Flask(__name__)
app.debug = True
@app.route("/")
def index():
conn = POOL.connection()
cursor = conn.cursor()
sql = 'select id,name,url from article limit 10'
cursor.execute(sql)
res = cursor.fetchall()
return jsonify({"code": 200, "msg": "成功", "result": res})
-没有--->一个请求--->就是一个新的连接
-django中引入连接池--->自行搜索
1 写个类,继承Form,在里面写字段
2 requset.POST 要校验的数据 form=MyForm(request.Post) form.is_valiad()
3 可以在模板上,快速生成form表单
flask-script
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
app.debug = True
manager = Manager(app)
@manager.command
def custom(arg):
"""自定义命令
python manage.py custom 123
"""
print(arg)
@manager.option('-n', '--name', dest='name')
@manager.option('-u', '--url', dest='url')
def cmd(name, url):
"""
自定义命令(-n也可以写成--name)
执行: python manage.py cmd -n lqz -u xxxx
执行: python manage.py cmd --name lqz --url xxx
"""
print(name, url)
@app.route('/')
def index():
return 'index'
if __name__ == '__main__':
manager.run()
新版基于click
-运行flask flask --app py文件名字:app run
flask --app py文件名字:app run
@app.cli.command("create-user")
@click.argument("name")
def create_user(name):
print(name)
flask --app 7-flask命令:app create-user lqz
flask create-user lqz
django中自定制命令
management/commands/
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = '命令提示'
def handle(self, *args, **kwargs):
命令逻辑
python manage.py py文件(命令名)
信号
request_started = _signals.signal('request-started')
request_finished = _signals.signal('request-finished')
before_render_template = _signals.signal('before-render-template')
template_rendered = _signals.signal('template-rendered')
got_request_exception = _signals.signal('got-request-exception')
request_tearing_down = _signals.signal('request-tearing-down')
appcontext_tearing_down = _signals.signal('appcontext-tearing-down')
appcontext_pushed = _signals.signal('appcontext-pushed')
appcontext_popped = _signals.signal('appcontext-popped')
message_flashed = _signals.signal('message-flashed')
signal:信号--》flask中的信号,django中也有
Semaphore :信号量,多把锁,https://zhuanlan.zhihu.com/p/489305763
import threading
def task(semaphore):
semaphore.acquire()
try:
print("Accessing shared resource")
finally:
semaphore.release()
semaphore = threading.Semaphore(5)
threads = [threading.Thread(target=access_resource, args=(semaphore,)) for _ in range(50)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
内置信号使用
from flask import Flask, signals, render_template
app = Flask(__name__)
def render_logger(*args, **kwargs):
print(args)
print(kwargs)
app.logger.info("模版渲染了")
signals.template_rendered.connect(render_logger)
def index():
name = "xxxx"
return render_template("indexs.html", name=name)
app.add_url_rule("/", view_func=index)
自定义信号
from flask.signals import _signals
print_args = _signals.signal('print_args')
def lqz(*args, **kwargs):
print(args)
print(kwargs)
print('我执行了')
print_args.connect(lqz)
@app.route('/home')
def home():
print('xxxxxxxxx')
print_args.send(value='xxxxxxxxx')
return 'home'
信号的实际用途
django中如何使用信号
from django.db.models.signals import pre_save
def callBack(*args **kwargs):
print(args)
print(kwargs)
instance=kwargs.get('instance')
pre_save.connect(callBack)
flask-cache
参考:https://flask.palletsprojects.com/en/3.0.x/patterns/caching/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现