Falsk框架?
内部采用了
1.模板引擎jinja2
2.werkzeug路由
3.itsdangrous token加密模块
4.click 命令终端
5.flask本身
其他的需要必须进行扩展自己安装
Flask的扩展包?
Flask-SQLalchemy 数据库操作orm
Flask-RESTful:api框架
script 插入脚本(淘汰)
migrate 管理迁移数据库
Session:session储存方式制定
Login:认证用户状态 (django内置auth模块,用户实现退出登录)
OpenID 认证oauth 第三方授权
JSON-RPC 远程调用
Mail:邮件
WTF:表单生成模块 基本不用 防御机制
Banble:提供国际化本地化支持
OpenID:认证
Bootstrap:继承前端 booststrap框架
Moment:本地化日期和时间
Admin:简单而扩展的管理接口的框架 需要配合booststrap框架
marshmallow 序列化器 类似于django的序列化器
包的中文文档总结
https://wizardforcel.gitbooks.io/flask-extension-docs/content/index.html
Flask生命周期
客户端(http)->web服务器(转发协议)->wsgi(把请求协议转为request对象)
->全局钩子->路由->视图->路由->全局钩子->wsgi应用(把response转为响应文本)
->web服务器(http响应)->客户端
Flask开始
Flask-基本使用
1.创建虚拟环境
virtualenv 虚拟环境名称 --python=python3.9 # 指定python包
2.在pcharm中配置虚拟环境,直接就进入了虚拟环境的状态
3.也可以通过
activate 进入
deactive 退出
# 导入文件类
from flask import Flask
# 初始化 __name__ 拿到的就是当前py的文件名称入口名称
app = Flask(__name__)
@app.route('/') # 可以通过route装饰器 绑定路由和函数的关系
def index():
# 视图的名字不能重复,重复报错
# 视图的返回值包装为html内容返回给客户端
return '测试' # 支持html内容
if __name__ == '__main__':
# 运行 相当于django的runserver
# host 路由 debug 开启debug模式 port端口设置
app.run(host='120.0.0.1', debug=True, port=5000)
Flask中的对象参数?
app = Flask(__name__) 内部的参数
import_name: # flask启动项目的包模块 传入__name__就可以,决定flask在访问静态文件的查找路径
静态文件的url路
static_url_path:默认为 /static
# static_url_path='/python',
# 访问: http://127.0.0.1:5000/python/123.png
# 默认访问: http://127.0.0.1:5000/static/123.png 如果不设置的情况下默认参数stati
静态文件的存储文件夹 默认static
static_folder: t.Optional[t.Union[str, os.PathLike]] = "static"
模板文件夹 可以不传默认templates
template_folder: t.Optional[str] = "templates",
host 路由默认值 debug 开启debug模式 port端口设置有默认值
app.run(host='120.0.0.1', debug=True, port=5000)
Flask项目加载配置方法?
1.可以通过key val字典格式添加站点配置
app = Flask(__name__)
app.config['DEBUG'] = True # 添加配置 传入大写
可以写入的参数必须大写
配置信息都放在这里面(按照 字典类型处理是可以的)
{
'ENV': 'production',
'DEBUG': True,
'TESTING': False,
'PROPAGATE_EXCEPTIONS': None,
'SECRET_KEY': None,
'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days=31),
'USE_X_SENDFILE': False,
'SERVER_NAME': None,
'APPLICATION_ROOT': '/',
'SESSION_COOKIE_NAME': 'session',
'SESSION_COOKIE_DOMAIN': None,
'SESSION_COOKIE_PATH': None,
'SESSION_COOKIE_HTTPONLY': True,
'SESSION_COOKIE_SECURE': False,
'SESSION_COOKIE_SAMESITE': None,
'SESSION_REFRESH_EACH_REQUEST': True,
'MAX_CONTENT_LENGTH': None,
'SEND_FILE_MAX_AGE_DEFAULT': None,
'TRAP_BAD_REQUEST_ERRORS': None,
'TRAP_HTTP_EXCEPTIONS': False,
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http',
'JSON_AS_ASCII': None,
'JSON_SORT_KEYS': None,
'JSONIFY_PRETTYPRINT_REGULAR': None,
'JSONIFY_MIMETYPE': None,
'TEMPLATES_AUTO_RELOAD': None,
'MAX_COOKIE_SIZE': 4093
}
2.加载站点配置的方式 字典方式加载的方式进行加载
app = Flask(__name__)
config = {
'DEBUG':True
}
app.config.update(config)
3.类方式加载
app = Flask(__name__)
class Config:
DEBUG = True
app.config.from_object(Config)
4.文件方式加载
在文件中编写对应配置
config.py
DEBUG=True
app = Flask(__name__)
app.config.from_pyfile('config.py') #(文件路径)
5.从环境变量中进行加载
... 见官方
Flask-路由使用
路由是一种 视图与路由的1对1的映射关系
# 路由和视图全局唯一
路由重复,只会显示第一个路由的试图
视图重复会报错
# 不设置methods 的话 默认get请求
@app.route(rule='/', methods=['GET','POST'])
def index():
'''
rule 路由的写法 可以 rule = / 也可以 /
methods = ['POST','GET'] 允许多个请求方式或者单个请求方式 控制请求方式
:return:
'''
return '测试' # 支持html内容
app.url_map # 返回全部的项目中的url 是一个flask封装的map对像
app.url_map.iter_rules() # 返回一个迭代器可以进行循环
form item in app.url_map.iter_rules():
item.rule # 是路由对象
item.endpoint # 是当前路由的视图名称
Flask-路由参数
@app.route(rule='/index/<id>', methods=['GET'])
def index2(id):
'''
路由传递(单个)
127.0.0.1:8000/index/123
:param id: 接受路由传入的参数id
:return:
'''
return '当前传入的参数是%s' % id
@app.route(rule='/index/<id>/<cid>', methods=['GET'])
def index3(id, cid):
'''
路由传递参数多个
127.0.0.1:8080/123/456
:param id: 第一个参数
:param cid: 第二个参数
:return:
'''
return '当前传入的参数是%s-%s' % (id, cid)
# 接受的参数默认是 字符串
路由转换器
1.默认
string any path int float uuid
对路由传入的参数的限定格式转换 默认字符串
int 整形
uuid uuid类型
string 字符串
float 浮点性
path 路径格式 例如:asdas/sadada
@app.route('/index/<int:id>/<int:cid>', methods=['GET'])
def index(id, cid):
print(type(id), type(cid)) # int类型
return 'hello word'
2.自定义路由转换器(限制一些访问规定)
# 1.导入路由转换器父类
from werkzeug.routing.converters import BaseConverter
# 2.创建类
class MobileConverter(BaseConverter):
regex = r'1[3-9]\d{9}' # 必须是正确的手机号格式
# 3.注册自定义路由转换器
app.url_map.converters['mobile'] = MobileConverter
# 4.使用路由转换器
@app.route('/index/<mobile:cid>', methods=['GET'])
def index(id,cid):
pass
3.动态设置路径规则更加的灵活 # (高级用法)
# 1.导入路由转换类
from werkzeug.routing.converters import BaseConverter
# 2.创建路由转换类
class MobileConverter(BaseConverter):
'''
map : 路由对象
args :接收位置参数
kwages :接收关键字参数
'''
def __init__(self, map, *args, **kwargs):
super().__init__(map, args, kwargs)
self.regex = args[0]
# 3.注册路由转换类
mobile 相当于 MobileConverter类的别名 指向当前MobileConverter类
app.url_map.converters['mobile'] = MobileConverter
# 4.使用路由转换类
动态设置定路由规则:
<mobile(name = r"1[3-9]\d{9}"):msi> 会被mobile注册的自定义路由规则类的kwargs给接收 {'name':'1[3-9]\\d{9}'}
<mobile(r"1[3-9]\d{9}"):msi> 会被mobile注册的自定义路由规则类的args给接收 ( '1[3-9]\\d{9}',)
# mobile(r"1[3-9]\d{9}")相当于给注册的类进行实例化
@app.route('/index/<mobile(r"1[3-9]\d{9}"):msi>', methods=['GET'])
def index(msi):
return 'hello word'
Flask请求与响应参数
请求参数(接收的内容)
from flask import request # 全局对象
1.request.files # 记录上传的文件列表(表单) ImmutableMultiDict
request.files.get('文件key') # 获取单个
request.files.getlist('文件key') # 获取同key下的多个返回列表
使用FileStorage对象提供的save方法,从内存中将图片存储到本地
file = request.files.get('file') # 获取
file.save('./file.png') # 保存
3.request.headers # 获取请求头
4.request.data # 记录请求体的数据并且转为字符串 字节b'' 原始数据其他的数据如:xml
request.data # 需要进行转换数据才能使用
json.loads(request.data) # 转换为正常dict类型
5.request.form # 记录html的表单数据(表单) ImmutableMultiDict
request.form.get('参数') # 获取单个
request.form.getlist('参数') # 获取同一个key的多个值 列表
6.request.args or request.query_string
# 记录url的查询字符串 也可以使用query_string ImmutableMultiDict
路由:http://127.0.0.1:8080/?name=666&name=777
request.args : ImmutableMultiDict([('name', '666')]) 对象字典get取值
request.query_string : b'name=666' 字节
request.ages.get('name') # 只能获取单个值(第一个值) 666
request.args.getlist('name') # 可以获取多个值 ['666','777']
7.request.method
# 记录http的请求方法(获取url的请求格式)
路由:http://127.0.0.1:8080/
request.method :GET
8.request.json # 获取ajax的json数据
request.json # 返回的不同的dict数据
9.request.is_json # 判断传入数据是不是ajax请求json格式
request.is_json 返回 True/Fasle
10.request.path # 获取当前访问地址
获取当前访问的路径不加端口和ip
11.request.url # 获取请求的完整url
12. request.environ # 获取环境变量
# 可以使用dir(request) #查看方法
响应参数(返回的结果)
1.数据响应
from flask import Flask, make_response, Response, jsonify
1.响应html
在视图中直接 return 文本 响应的就是html代码
# 直接返回元祖(响应内容,响应状态码)
return 'hello flask',201(返回状态码) # 响应内容并且返回状态码
# 通过make_response返回响应对象
return make_response('hello flask',201)
# response 返回响应对象(最底层的相应)
return Response('hello flask',201)
2.响应json
# 使用原生的json模块(如果不添加Content-Type会被当成html) 不建议使用麻烦
data = {'name':'小明'}
return json.dumps(data),200,{'Content-Type':'application/json'}
# 使用flask提供的方法jsonify
data = {'name':'小明'}
jsonify(data)
3.响应媒体图片
需要设置{'Content-Type':'image/png'} 就可以进行返回
with open('file.png','rb') as f:
data = f.read()
return data,200,{'Content-Type':'image/png'} # MIME类型
2.页面响应 链接或者重定向
from flask import Flask, request,redirect,url_for
1.站内跳转
@app.route(rule='/', methods=['get', 'post'])
def index():
if request.args.get('token'):
return '个人中心'
# 1.基于redirect 参数就根据url地址,跳转到任意路径下
return redirect('/login')
# 2.基于url_for 根据属视图名称跳转到当前视图路径下
# 根据flask 的路由表生成的 app.url_map()
return redirect(url_for('login'))
@app.route('/login')
def login():
return '登录s视图'
2.站外跳转
'''
301:永久重定向
302:临时重定向
'''
return redirect('https://www.baidu.com',302)
3.带参数跳转
1.使用redirect方式将参数携带过去到/sms/路由下
return redirect('/sms/13027630227')
@app.route(rule='/sms/<int:ppp>')
......
2.使用url_for携带参数跳转
# url_for('视图名称',视图参数='传入的参数')
@app.route(rule='/')
def index():
url = url_for('sms',ppp='13027630227') # 进行了拼接
return redirect(url)
@app.route(rule='/sms/<int:ppp>')
def sms(ppp):
return '给%s发送短信' % ppp
3.自定义响应头
内容,状态码,响应头
return 'hello flask',201,{'Company':'flask'} # 自定义响应头不能中文
Flask-Cookie与Session
保护用户的状态,点击浏览器开启,关闭浏览器关闭
http无状态协议,浏览器请求服务器是无状态
无状态:
指一次用户请求时,浏览器 服务器无法知道这个yoghurt做了什么对于服务器而,客户端每次请求都是一个新的请求
无状态原因:
浏览器与服务器是socket套接字通信,服务器将请求的结果数据返回给浏览之后,会关闭当前的链接,而客户端也会处理网页面后销毁页面对象,
主要是为了保存确认用户是否登录,浏览过那些商品
状态保存:
1.在客户端存储 cookie token【jwt,oauth】
2.在服务器保存 session,数据库
Cookie
每次请求都会将cookie发送给服务器
from flask import Flask, make_response, request
@app.route(rule='/set_cookie')
def set_cookie():
# 通过make_response设置
# 在响应对象中进行设置cookie max_age= cookie的过期时间按照秒
response = make_response('cookie设置')
response.set_cookie('user_id', '1')
response.set_cookie('user_name', 'wkx', max_age=3600)
return response
@app.route(rule='/get_cookie')
def get_cookie():
# 通过request获取cookie
user_id = request.cookies.get('user_id')
user_name = request.cookies.get('user_name')
print(user_id, user_name)
return "cookie获取"
@app.route(rule='/del_cookie')
def del_cookie():
# cookie保存在客户端的,无法直接删除cookie
# 只能告诉浏览器过期了内容设置为空,让浏览器自动删除,让时间变为0
response = make_response('cookie删除')
response.set_cookie('user_id', '',max_age=0)
response.set_cookie('user_name', '', max_age=0)
return response
Session
session依赖于cookie 加密保存到session中
基于token的方式存放在客户端中
from flask import Flask, session
app.config['SECRET_KEY'] = '加密' # 基于cookie设置需要设置秘钥
@app.route(rule='/set_session')
def set_session():
"""设置session"""
session['username'] = '4164646'
session['userid'] = '4164646'
return 'set_session'
@app.route(rule='/get_session')
def get_session():
"""获取session"""
username = session.get('username')
userid = session.get('userid')
print(userid,username)
return "get_session"
@app.route(rule='/del_session')
def del_session():
"""删除session"""
session.pop('username')
return 'del_session'
# 注意:
在设置flask配置中得参数'PERMANENT_SESSION_LIFETIME'需要配置session.permanent = True才会生效
session.permanent = True # 设置这个参数 session的过期时间才会生效
FLASK-全局钩子
中间件
作用:
1.在项目启动时,建立数据库链接,或者创建连接池
2.在客户端请求开始时,对用户进行身份识别权限校验
3.在请求视图返回数据的时候,指定转换数据格式或者记录操作日志
1.before_first_request
在处理第一个请求前执行,项目被运行第一次被客户端请求执行的钩子
# 数据库初始化 加载一些可以延后引入的全局配置
@app.before_first_request # 写法1 2.3之前使用
def before_first_request():
"""启动项目时首次被访问 @app.before_first_request 全部的函数(只会执行一次作为初始化使用)"""
print('执行当前before_first_request')
app.before_first_request_funcs.append(before_first_request) # 写法2 2.3之后使用
2.before_request
在每一次客户端请求来之前都会进行执行
@app.before_request
def before_request():
"""每次在请求之前会执行,只要请求视图都会执行 before_request装饰的函数(每次访问视图之前的操作)"""
print('执行当前before_request')
3.after_request
如果没有抛出错误情况下,每一次请求执行视图结束后,就会直行
接收一个参数,视图的相应参数
# 加工一些响应头返回
@app.after_request
def after_request(response):
"""每次客户端访问之后,都会执行after_request装饰的函数(因为在视图后,需要将响应体返回)
返回数据加工或格式转换 日志记录
response:响应体
"""
print('after_request')
response.headers['....'] = .....
return response
4.teardown_request
每一次请求后都会执行,接收一个错误的信息,只有debug=false 才会接收异常参数
@app.teardown_request
def teardown_request(error):
"""
在客户端访问服务端报错后 获取执行错误的结果
就会自动执行teardown_request装饰的函数 接收一个error 本次结果的异常
error:本次出现的异常
在2.2之前 DEBUG = False才会执行teardown_request装饰函数
"""
print('after_request')
print(error)
Flask-抛出异常
分离不分离都可以使用
1.主动抛出异常 abort 是主动的将异常抛出
参数1:响应状态码
参数2: 页面的提示信息
from flask import Flask, abort
app = Flask(__name__)
app.config['DEBUG'] = True
@app.route(rule='/')
def set_session():
print('执行视图')
abort(401,'呵呵呵权限有问题呦') # 元祖方式
abort(401,{'error':123456}) # 字典方式
return '执行视图'
2.捕获错误信息
通过app.errorhandler装饰器进行捕获
当程序处理错误状态码时,就会调用该装饰器返回错误信息
app.errorhandler('异常类') 参数可以接收一些抛出的异常类
app.errorhandler('状态码') 也可以接收一些状态码
1.被动抛出异常被捕获到
@app.route(rule='/')
def set_session():
try:
print(hello) # 出现异常
except Exception as e:
raise NameError(e) # 抛出异常
return '使用try捕获异常并且抛出异常'
@app.errorhandler(NameError) # 接收异常
def NameErrorFunc(exc):
"""
针对与变量命名异常
:param exc: 接收的错误信息 异常的实例对象
:return: 错误信息的状态
"""
print(dir(exc))
print(exc.__traceback__) # 提示的对象 可以循环进行打印
print(exc.args) # 获取抛出的描述信息(元祖) 拿不到abort错误描述
return {'code': 500, 'error': str(exc)} # 返回json结构的数据
2.主动抛出异常
@app.route('/error')
def error():
abort(400, '视图异常')
return '主动抛出异常'
@app.errorhandler(400)
def Func_400(exc):
"""出现400错误那么就会 调用当前装饰器的函数抛出异常"""
print(dir(exc))
print(exc.code) # 拿到abort错误的状态码
print(exc.description) # 拿到abort的错误描述
return {'code': 400, 'error': str(exc)}
# 关于状态码问题:
@app.errorhandler(404)
如果不是abort主动抛出的异常 也会被捕获到
也可以是系统抛出的异常,也会被捕获到
404 访问不存在的路由就会被捕获到
# 关于raise抛出异常
class 自定义的error类(Exception):
pass
raise 自定义的error类('自定义错误')
@app.errorhandler(自定义的error类) # 也能捕获到
Flask-终端启动方式
关于flask开发阶段
app.config
在开发环境下 ENV = production
# 注意:
# 设置终端启动命令时,需要进行当前启动flask 的入口目录下进行设置
1.linux环境
# 需要在命令行设置
export FLASK_ENV = development # linux下设置的2.3环境不适用
export FLASK_DEBUG = True # 2.3
# 设置run 启动
export FLASK_APP = 启动文件的py文件 # linux下启动
可以通过
flask run --host 0.0.0.0 --port 5000 进行启动
2.win环境
set FLASK_ENV = development # 2.3版本以下
set FLASK_APP = 启动文件的py文件
set FLASK_DEBUG = True # 2.3 设置生产环境还是开发环境
可以通过
flask run --host 0.0.0.0 --port 5000 进行启动
其他命令
flask db [命令] 执行数据库迁移
flask routes 显示程序的路由
flask run 运行开发服务器
flask shell 在程序上下文运行shell exit() # 退出
生产环境
FLASK_DEBUG = FLASE
FLASK_APP = 启动文件的py文件
给 uwsgi使用 flask run --host 0.0.0.0 --port 5000 进行启动
其他命令
flask routes 查看当前服务下的路由信息
flask shell 进入交互模式 进入上下文
自定义终端命令
from flask import Flask
import click # 必须导入当前包
app = Flask(__name__)
app.config['DEBUG'] = True
# 自定义添加命令到命令终端中
@app.cli.command('faker')
@click.argument('data',type=str, default='user')
@click.option('-n', 'number', type=int, default=1, help='生成的数据量')
def flask_command(data, number):
print('添加测试参数')
print('生成数据类型%s' % data)
print('生成数据量:number=%s' % number)
@app.route(rule='/')
def set_session():
return '使用try捕获异常并且抛出异常'
if __name__ == '__main__':
app.run(port=8080, )
解释:
1.需要在终端中设置了FLASK_APP,就可以进行使用
2.相当于一个自定义的终端命令 与 flask run 一样 falsk faker(就执行)
app.cli.command('faker')
1.接收的位置参数
2.1.位置参数的名称 2.位置参数的类型(int,bool,srt,list) 3.位置参数的默认值
3.执行 flask faker 1(位置参数) # 那么位置参数 1 就会被data接收 (有几个位置参数那么就要在终端命令中写几个)
4.需要几个位置参数就设置几个名称不能为python固定名称不能重复
click.argument('data',type=str, default='user') 1
click.argument('data2',type=str, default='user2') 2
....
....
1.选项参数
2.1.简写的命令 2.选项参数名称 3.类型 4.默认值 5.说明
3.执行时 flask faker 1(位置参数) -n 123456(选项参数) # 那么选项参数会被number接收
click.option('-n', 'number', type=int, default=1, help='生成的数据量')
1.函数
def flask_command(data, number):
"""这里的内容作为自定义命令的说明"""
data:接收的位置参数
number:接收选项参数
# 自定义的逻辑 可以实现如 django一样 django-damin startapp 新app程序 创建
那么在终端中可以使用
flask 查看注册的自定义命令是否成功
Flask-上下文概念
flask 的上下文对象有两种:
作用:相当于一个容器,保存flask程序在运行中的一些(变量 函数 类 对象信息)
1.请求上下文对象
request context
2.应用上下文对象
application context
application:指定时当服务端调用app=Flask(__name__)创建这个对象app
request:当每次发送http请求时 wsgi server调用 Flask.__all__()(将类作为一个函数加()执行),在falsk内本次客户端中创建request对象
application 表示响应wsgi请求的应用本身,request表示服务器每次响应客户端的http请求
application的声明请求周期大于request,一个application存活的期间,发生多次http请求,会存在多个request对象
请求上下文对象
请求上下文的对象:
request,session
当前的请求上下文对象是在每一次请求时都会进行刷新,所以内部的数据是不同的
只有客户端访问服务器时才会产生请求上下文对象
request
封装http请求的内容,主要针对http请求 如 user = request.ages.get('user') 获取get请求
session
用来记录会话的信息,主要针对用户的信息,session['name'] = user.id 用来记录用户的状态信息,同时可以通过session.get('name')获取
# 注意:请求上下文提供变量和方法函数类对象,只能在视图中或者被视图调用的地方使用,没有发生客户端请求时,会报错超出上下文请求范围
def test():
print(request) # 请求上下文对象【request|session】 只能被视图调用 或者 间接调用使用
@app.route(rule='/')
def set_session():
print(request)
print(session)
test()
return '使用try捕获异常并且抛出异常'
应用上下文对象
帮助reqeust获取当前flask的引用相关信息,ta是伴request而生的,随request而灭
应用上下文:
current_app,g # 可以 进行写入一些变量到里面 current_app.age = 18 ,在其他的视图中是可以调用的
# current_app: 为了方便request请求时使用当前的app对象
app=Flase(__name__) 创建时
current_app 同时创建的current_app代理对象 # 属于视图内部调用的对象
app is current_app # False 内存地址不相同
app == current_app # Ture 同一个对象
如果在视图外部使用当前的current_app对象需要构建应用上下文环境
对当前对象只能在 视图中使用或者间接使用
with app.app_context(): # 才能使用
print(current_app)
# g 全局数据存储对象 用于保存服务端存储的全局变量数据 基于客户端的全局变量 (只限于本次请求)
from flask import g
def test():
print(g.name) # 获取数据
@app.route(rule='/')
def set_session():
print(g)
g.name = 'wkx' # 存储数据
test()
return '使用try捕获异常并且抛出异常'
# 每个客户端都有自己的全局变量g g对象是隔离的
请求上下文与应用上下文区别
请求上下文:保存了客户端和服务端交互的数据,http的请求
应用上下文:flask应用程序运行时,保存的一些配置信息,路由 程序名 数据库链接 应用信息
应用上下文提供对象,可以直接在请求上下使用,如果请求上下文进行外调需要执行
with app.app_context() 创建一个上下文的环境才能使用
Flask-模板引擎JinJa2
需要使用falsk提供的render_template封装了模板引擎
render_template('模板的文件名','键值对(模板的使用数据)')
1.需要在创建app时指定模板引擎的文件
app = Flask(__name__,template_folder='templates')
# 如果不指定那么默认就是template文件
2.render_template,render_template_string 区别
2.1.render_template
# 根据参数1文件路径,读取html模板内容,返回渲染后的html页面
2.2.render_template_string
# 基于参数1的的内容渲染模板 优势不用前端修改,直接在数据库中修改
render_template_string ('str内容不识别模板路径识别字符串')
例如:
@app.route(rule='/')
def set_session():
title = '网页标题'
content = '网页正文内容'
tpm = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ title }}</h1>
<p>{{ content }}</p>
</body>
</html>
"""
html = render_template_string(tpm, **locals())
print(html)
return html
3.使用模板语法传入内容
@app.route(rule='/')
def index():
return render_template("index.html",title='网页标题')
<h1>{{ title }}</h1> # 使用传入的键值对title变量
4.多个内容 **locals() 将多个键值传入模板
@app.route(rule='/')
def index():
title = '网页标题'
content = '网页正文内容'
return render_template("index.html",**locals())
# 在index.html进行使用
<h1>{{ title }}</h1>
<p>{{ content }}</p>
模板语法
1.输出代码块
{{ 变量名 }} # 可以输出 dict set 元祖 str int bool 等等基本类型 复杂类型
例如复杂类型:
dic = {
'name':123,
"age":456
}
<p>{{dic.get('name')}}</p> # 可以使用python的内置类型的原生方法进行取值,list,set,都可以使用
<p>{{dic.name}}</p> # 也可以使用.语法进行取值(js语法一样)
{{ 也可以渲染flask内的对象 }}
from flask import request,session,g 等等
<p>{{request}}</p>
<p>{{session}}</p>
<p>{{g}}</p>
<p>{{ config }}</p> # 拿到flask的配置信息
2.注释
{# 注释不会再页面中渲染 #}
3.url_for
在模板中使用url_for
<p>{{ url_for('user',uid=3) }}</p>
user 视图必须存在要不然会报错
/user/3 # 动态路由
# 视图:
@app.route(rule='/user/<int:uid>')
def user(uid):
pass
# 如果视图中不存在/<int:uid>接收参数
<p>{{ url_for('user',uid=3) }}</p>
/user?uid=3 # url就会变为带有请求参数
# 视图:
@app.route(rule='/user')
def user():
pass
4.流程控制语法 控制代码块 # 与python一模一样
if / elif / else / endif 判断
for / else / endfor 循环
4.1循环
lis = [1,2,3]
lis = []
{% for i in lis %}
# loop.index 获取循环的下标 从1开始
# loop.first 如果是第一次迭代 为True
# loop.last 最后一次迭代为True
# loop.cycle('男-为True',"女-为False") 在数据库中假设1为nan 0为女 布尔就是True False loop.cycle就是处理 True False的
<p>{{ loop.index }} {{ i }}</p>
{% else %}
<p>没有哦</p> # lis为空那么就会直行当前else语法(与python的一样)
{% endfor %}
4.2判断
start = False
{% if start %}
<p>1234556</p> # ture 显示
{% else %}
<p>666</p> # false 显示
{% endif %}
模板过滤器语法内置
变量名 | 过滤器 | .... # 过滤器左边的内容作为过滤器的第一个参数
1.safe
lis = "<h1>66666</h1>"
<p>{{ lis|safe }}</p> # safe 告诉flask 不用转义直接使用 默认是转义的防止用户输入js代码在网站中执行
2.reverse 数据翻转 (列表元祖复杂类型会为生成器需要循环)
lis ='python'
<p>{{ lis | title }}</p>
3.title 首字母大写
lis ='python'
<p>{{ lis | title }}</p>
4.upper 大写 lower 小写
lis ='python'
<p>{{ lis | upper }}</p>
5.d or default d默认值
如果lis不存在 那么在模板中显示的值就是默认值中的数
<p>{{ lis | default('2131323') }}</p>
6.字符串截断
lis ='asdadsawqxzzcz'
<p>{{ lis | truncate(5,'默认参数False 如果传入True那么就是强制截断字符中的空格也会算上') }}</p> 将截断内容在html中以..显示 as...(最低截断不能小于3)
7.format 格式化输入
<p>{{ '%s=%s'|format('name','wkx') }}</p> # name=wkx
8.striptags 将选中的数据中的html标签全部去掉 # 不能使用大于号小于号
<p>{{ '<h1>sadassda</h1>'|striptags }}</p> # sadassda
9.first 获取列表的第一个元素 set 元祖 列表 字典(只能获取第一个kv的k) 字符串
lis =[1,2,3,4,5,6,7,8,9]
<p>{{ lis | first }}</p> # 1
10.last 获取列表的最后一个元素 set 元祖 列表 字典(只能获取第一个kv的k) 字符串
lis =[1,2,3,4,5,6,7,8,9]
<p>{{ lis | last }}</p> # 9
11.length/count 获取元素长度 set 元祖 列表 字典(只能获取第一个kv的k) 字符串
lis =[1,2,3,4,5,6,7,8,9]
<p>{{ lis | length }}</p> # 9
12. sum 获取序列类型的求和 set 元祖 list
<p>{{ lis | sum }}</p>
lis =[1,2,3,4,5,6,7,8,9]
<p>{{ lis | sum }}</p> # 45
13.sort 获取列表的排序 支持字典按照key set list 元祖
lis =[1,2,3,4,5,6,7,8,9]
<p>{{ lis | sort }}</p> sort(reverse=true) 倒叙
sort(attribute="age") # 按照字典的key age 进行排序
模板过滤器语法-过滤块
语法:
{% filter 过滤方法 %} # 会将当前范围内的全部根据过滤器进行转变
<p>{{ 'a,baaa' }}</p> # 变量
<p>{{ 'a,baaa' }}</p>
<p>{{ 'a,baaa' }}</p>
<p>{{ 'a,baaa' }}</p>
{% endfilter %}
例如:
{% filter upper %}
<p>{{ 'a,baaa' }}</p> # A,BAAA 全部变为大写字母
<p>{{ 'a,baaa' }}</p>
<p>{{ 'a,baaa' }}</p>
<p>{{ 'a,baaa' }}</p>
{% endfilter %}
自定义过滤器
过滤器本质就是函数,当模板内置的过滤器不能满足当前的要求,就可以自定义过滤器
1.通过flask引用程序对象app.add_template_filter进行注册
2.通过装饰器进行注册
# 注意:不能与内置的过滤器进行重名,会将原有的过滤器进行覆盖
# 也就是创建一个函数注册到过滤器中
1.app.add_template_filter('注册过滤器的函数','过滤器的名字')
例如:
def do_fixed(data): # 注册过滤器的函数
'''
:param data: 接收模板传入的参数
:return:
'''
return 1 # 返回为1
app.add_template_filter(do_fixed, 'fixed') # 将过滤器函数注册
在模板中使用
<p>{{ 'llll'|fixed }}</p> # 显示 1
2.批量导入自定义过滤器(适用于注册形式)
filter.py # 自定义过滤器文件
def do_xx(data):
pass
def do_xx2(data):
pass
FILTERS = {
'xx':do_xx,
'xx2':do_xx2
}
from filter import FILTERS # 在app程序中导入
# 批量注册自定义过滤器
for key,val in FILTERS:
app.add_template_filter(val, key)
3.通装饰器进行注册
@app.template_filter('过滤器名称')
def 函数(data):
'''
:param data: 接收模板传入的参数
:return:
'''
pass
例如:
@app.template_filter('fixed')
def do_fixed(data):
'''
:param data: 接收模板传入的参数
:return:
'''
return 1
模板继承语法
与vue的导入组件导入是类似的
vue:将公共的组件创建为 xx.vue文件 如果使用到了公共组件就将它进行导入,注册 使用
模板继承:
做一个公共使用的html页面,页面中留出一些公用的位置,这也位置的内容需要根据业务的不同变化
在模板中遇到的情况:
多个模板使用同一个底和顶
多个模板具有相同的代码内容,但是内容不同
多个模板具有相同的html代码块内容,侧边栏
目的: 重复的使用模板中的公共内容,一般情况主要使用网站的顶部菜单,侧边栏,广告,这些内容可以定义到父模板中,子模板直接继承,不需要重复书写
# 使用的是block 相当于在父模板中挖了一个坑,当子模板继承父模板是,可以对坑的位置填补需要的内容
# 注意:
1.子模板使用extends声明在我为那个父模板填坑(每个子模板只能为继承一个父模板)
2.父模板定义的区域,会在子模板中重新定义,在字母本中调用父模板的内容可以使用super()调用父模板声明的区域内容
1. base.html // 父模板文件
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{{ title }}
</title>
</head>
<body>
<h1>京东商城</h1>
<div>
// 在父模板挖的一个坑
{% block content %}
<p>父模板的默认内容</p> 如果子模板没有填坑那么就会使用父模板默认的
{% endblock content %}
</div>
<h1>我是底部内容</h1>
</body>
</html>
2.index.html // 子模板文件
// 1.需要导入父模板,知道子模板继承了那个父模板(基于template 寻找的父模板文件 注意路径) 存在嵌套文件: 嵌套文件夹/父模板.html
{% extends 'base.html' %}
// 2.对父模板的坑进行填写(如果没有填写那么就会使用父模板的默认内容内容)
{% block content %}
<p>我是首页</p>
{% endblock %}
3.视图
@app.route(rule='/')
def index():
title = '站点首页'
html = render_template("index.html", **locals())
return html
// 4.使用方法 *****
父模板:
{% block 坑的名字 %}
// 挖个坑,让子模板继承后进行填写
默认内容 // 子不填 我用自己的
{% endblock 坑的名字 %}
子模板 :
{% extends '继承父模本文件.html' %}
{% block 坑的名字 %}
// 我为父模板填坑(如果我不填,那么就会用父模板的内容)
{% endblock %}
//5.使用是的注意情况
1.不支持多继承,在同一个模板中只能使用一个extends
2.在子模板第一行使用extends 告知继承父模板
3.不能在模板中同时定义多个相同名称 block 会进行覆盖
4.当使用多个block 请为结束enblock标记相同与block名称 方便阅读
Flask-CSRF攻击防范
如果使用前后端不分离的情况防止csrf可以基于
pip install flask_wtf # 模块进行防止
1.将app注册到wtf模块中
from flask import Flask
from flask_wtf import CSRFProtect # 2.导入防范机制类
app = Flask(__name__, template_folder='templates')
app.config['SECRET_KEY'] = '防止CSRF攻击(仅限于前后端不分离)' # 1.添加配置
# 原理:在每次提交post请求的表单时,都会验证请求投头中是否存在csrf的token
csrf = CSRFProtect() # 3.实例化csrf
csrf.init_app(app) # 4.将app注册
2.在html表单中使用
会将csrf携带到视图中,如果存在验证通过,如果失败验证不通过
<form action="/send_money" method="post">
{# 使用令牌 #}
<input type='hidden' name="csrf_token" value="{{ csrf_token() }}">
账户: <input type="text" name="user">
密码: <input type="text" name="pwd">
<input type="submit" value="转账">
</form>
中文文档:
http://docs.jinkan.org/docs/flask-wtf/quickstart.html
构建flask工厂方式配置方式
from flask import Flask
class DefaultConfig: # 生产模式 所需要的全部参数
SECRET_KEY = ''
class DevelopmentConfig(DefaultConfig): # 调试模式下的参数
'''继承了生成模式的类'''
DEBUG = True
def create_flask_app(classobj):
# 启动配置
app = Flask(
__name__,
static_url_path='/python',
static_folder='static_folder'
) # 启动对象
app.config.from_object(classobj) # 类加载配置
app.config.from_pyfile('view/apps.py') # 文件加载配置(将重要的参数放到文件中,会覆盖将类中的重要参数进行覆盖)
return app # 返回flask框架的app对象
app = create_flask_app(DevelopmentConfig) # 将调试模式下的类存放
Flaks-蓝图使用
蓝图等价于django中的子应用程序(模块化思想)
特点:
每一个 app 都可以有多个蓝图
可以给每一个蓝图注册一个路由的前缀
蓝图可以有自己的模板静态等等自己的文件
需要在flask进行注册进去(必须注册,和django一样)
from flask import Flask, Blueprint
app = Flask(__name__)
# Blueprint('别名',__name__)
user_bp = Blueprint('user', __name__) # 1.创建蓝图对象
@user_bp.route('/login') # 2.使用蓝图对象注册视图 装饰器方式
def login():
return 'login'
# 3.将蓝图对象注册到app下 register_blueprint('蓝图对象','url前缀')
app.register_blueprint(blueprint=user_bp, url_prefix='/api')
if __name__ == '__main__':
app.run(debug=True)
# 访问地址 = register_blueprint 注册蓝图的url前缀 + @user_bp.route 注册的url
# /api/login
包形式蓝图
包中__init__.py文件
init文件:
from flask import Blueprint # 蓝图对象
from . import views
# Blueprint('别名',__name__)
# 相当于声明一个子app app = Flask(__name__)
users_bp = Blueprint('user_api', __name__)
# 使用add_url_rule进行注册url 视图 绑定视图到路由中
users_bp.add_url_rule(rule='/login', view_func=views.login)
users_bp.add_url_rule(rule='/user_get', view_func=views.user_get)
包中的views.py文件
def user_get():
return '登录'
def login():
return '注册'
项目入口文件manage.py
from flask import Flask
from user import users_bp # 导入
app = Flask(__name__)
app.register_blueprint(users_bp, url_prefix='/api') # 注册
if __name__ == '__main__':
app.run(debug=True)
蓝图运行原理
1.蓝图实际作用就是,充当 当前蓝图目录下所有视图和url路由地址绑定关系的临时容器。
2.在视图函数被蓝图对象.add_url_rule注册时,本质就是将视图与url地址的映射关系添加到蓝图的子路由列表中deferred_functions
3.蓝图本身没有路由机制,当蓝图的视图调用add_url_rule注册时,他是在蓝图对象内部中的deferred_functions(子路由列表)中添加了一个路由项(绑定关系)
4.当进行app.register_blueprint注册蓝图时,app实例对象就会将蓝图的deferred_functions列表中进行循环,将每一个路由项取出,并且app应用实例对象作为参数执行路由项对应lambda匿名函数,匿名函数直行后就会调用add_url_rule方法,将蓝图下的子路由列表暂存的路由添加到app的url_mao总路由列表中,所有用户可以flask中访问蓝图中的视图
# add_url_rule : 将全部的路由url与函数绑定的关系执行流程
'''
在内部调用了实例化蓝图对象中的add_url_rule对象
1.
接收参数(比较重要)
rule: url地址
view_func: 视图函数名称
进行了:
self.record( # 调用了内部的record方法 传入了一个lambda的匿名函数
lambda s: s.add_url_rule(
rule, url地址
endpoint, 别名
view_func, 视图名称
provide_automatic_options=provide_automatic_options,
**options, 其他参数
)
)
2.
def record(func...): 这个方法内部执行了将 匿名函数添加到deferred_functions列表中
self.deferred_functions.append(func)
3.
deferred_functions列表参数是蓝图类实例化init初始化的一个参数
'''
# register_blueprint 执行
'''
register_blueprint 在内部调用了第一个参数的(蓝图对象内的方法)方法
1.
blueprint.register(self, options) 将flask对象本身与剩余参数
2.
执行当前蓝图下的这个方法
def register(self, app: "Flask", options: dict)
3.
register方法中
基于app对象进行封装获取state对象
state = self.make_setup_state(app, options, first_bp_registration)
执行了make_setup_state传入了flaskapp与与剩余的其他参数
4.
执行了注册了访问的静态路由方式
state.add_url_rule(
f"{self.static_url_path}/<path:filename>",
view_func=self.send_static_file,
endpoint="static",
)
5.
将deferred_functions列表中进行循环(全部都是蓝图注册的路由和函数名称,匿名函数lambda)
将state传入 传入
for deferred in self.deferred_functions:
deferred(state)
6.在state对象中就是将类型了实例化
BlueprintSetupState(self, app, options, first_registration) 就是将对象纯初始化
7.
deferred(state)
lambda s: s.add_url_rule(
rule, url地址
endpoint, 别名
view_func, 视图名称
provide_automatic_options=provide_automatic_options,
**options, 其他参数
)
那么这个匿名函数的s也就是state
state.add_url_rule(而state本身就是flask的app对象)
BlueprintSetupState类中的
self.app = app
self.app.add_url_rule(
rule,
f"{self.name_prefix}.{self.name}.{endpoint}".lstrip("."),
view_func,
defaults=defaults,
**options,
)
flask.add_url_rule(将蓝图中的路由进行注册)
'''
url_for
form flask import url_for
url_for('蓝图名称.视图函数名称')
Flask-补充
1.提供下载功能
import os
import pathlib
import mimetypes
from flask import Flask,Response,make_response,send_from_directory
base_path = pathlib.Path(__file__).parent
app = Flask(__name__)
'''
下载的时候要注意的问题:
1.设置响应请求头的类型 : Content-Type 平常都是json格式,文件的话是其他的格式
2.告诉浏览器当前下载的作为浏览器的附件下载属性: Content-Disposition https://cloud.tencent.com/developer/section/1189916
'''
@app.route('/dow')
def dow():
path = os.path.join(base_path,'下载文件.txt')
file = open(path,mode='rb')
# response = make_response(file)
# response.default_mimetype = 'text/html'
# response['Content-Disposition']='attachment; filename="filename.txt"'
'''
path: 下载的文的路径 相当于 open(path,mode='rb') Content-Type: text/plain; charset=utf-8
filename:下载文件的名称和后缀 相当于请求头中的 filename="filename.txt
directory: 当前下载文件的父级路径
as_attachment : False则浏览器返回文件预览 如果该文件可以被浏览器渲染 response['Content-Disposition']='attachment;
'''
return send_from_directory(path=path,filename='下载文件.txt',as_attachment=False,directory=base_path)
@app.route('/dow2')
def uploaded_file():
path = os.path.join(base_path,'下载文件.txt')
f = open(path, "rb")
res = Response(f.readlines())
mime_type = mimetypes.guess_type(path)[0]
res.headers['Content-Type'] = mime_type
res.headers['Content-Disposition'] = "attachment; filename=filename.txt"
return res
if __name__ == '__main__':
app.run()
'''
资料案例
https://blog.csdn.net/li627528647/article/details/77544136
https://blog.csdn.net/qq_44198436/article/details/106922355
https://blog.csdn.net/WJ844908240/article/details/102517072
'''
Flase扩展包
Flask邮件模块
1.安装:pip install flask-mail
基本使用
import os
from flask import Flask
from flask_mail import Mail, Message
'''
qq 邮箱的授权码 hvijhzswucrjbeff
一般在邮箱中的设置中账户
POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务
开启 pop3的服务 会给一个授权码,就可以代替 发送邮件服务
'''
app = Flask(__name__)
app.config["MAIL_SERVER"] = "smtp.qq.com" # 邮箱的服务器的主机名和ip地址
app.config["MAIL_PORT"] = 465 # 设置邮箱端口为465
app.config["MAIL_USE_SSL"] = True # QQ邮箱需要开启SSL启动安全接层 谷歌需要开启MAIL_USE_TLS TLS 启动传输层协议
app.config["MAIL_USERNAME"] = "565151759@qq.com" # 发送者邮箱名
app.config["MAIL_PASSWORD"] = "hvijhzswucrjbeff" # 开启POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务返回的授权码 代替密码 使用这个邮箱代发邮件
mail = Mail()
mail.init_app(app) # 初始化当前的app对象到mail中去
# 发送的 文件
path = os.path.join(os.path.abspath(os.path.dirname(__file__)), '测试001.xlsx')
@app.route("/email")
def emailDemo():
"""
Message发送邮件信息, sender为发送者邮箱:读取的配置文件的中使用发送者邮箱, recipients为接受者邮箱:列表形式
"""
message = Message("测试邮件标题1000", sender=app.config["MAIL_USERNAME"], recipients=["565151759@qq.com"])
print(message)
message.body = "测试邮件的内容1000" # 设置内容
message.html = '<h1>123</h1>' # 设置大的标题
# 添加附件
# 打开文件
with app.open_resource(path) as doc:
# attach("文件名(名称需要转义)", "类型", 读取文件)
message.attach("001", 'application/octet-stream', doc.read())
# 调用send_email函数防止出现上下文问题
send_email(message)
return "发送成功"
# 防止上下文的问题使用 app.app_context()
def send_email(message):
with app.app_context():
# mail.send 调用这个方法 将message邮箱内容 对象进行发送
mail.send(message)
if __name__ == "__main__":
app.run(debug=True)
异步方式邮件(开启线程)
from threading import Thread
from flask import Flask
from flask_mail import Mail, Message
app = Flask(__name__)
app.config["MAIL_SERVER"] = "smtp.qq.com" # 邮箱的服务器的主机名和ip地址
app.config["MAIL_PORT"] = 465 # 设置邮箱端口为465
app.config["MAIL_USE_SSL"] = True # QQ邮箱需要开启SSL启动安全接层 谷歌需要开启MAIL_USE_TLS TLS 启动传输层协议
app.config["MAIL_USERNAME"] = "565151759@qq.com" # 发送者邮箱名
app.config["MAIL_PASSWORD"] = "hvijhzswucrjbeff" # 开启POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务返回的授权码 代替密码 使用这个邮箱代发邮件
mail = Mail()
mail.init_app(app)
# 执行命名函数,需要用线程进行调用
def sand_async_email(app, msg):
with app.app_context():
mail.send(msg)
def sand_email(app):
msg = Message('这是一个异步的发邮件方式', sender=app.config['MAIL_USERNAME'], recipients=['565151759@qq.com'])
msg.body = '你是个傻逼吗'
# 调用线程执行的方式
# 传入函数,传入参数 app 对象和 msg发送邮件内容对向
thr = Thread(target=sand_async_email, args=[app, msg])
thr.start() # 执行
return thr
# 使用线程去调用邮箱执行命令,速度更快
print(sand_email(app))
Flask_Migrate迁移
使用版本 2.7.0
1.导入包
from flask import Flask # 框架实例
from flask_sqlalchemy import SQLAlchemy # 数据库
from flask_migrate import Migrate # 迁移包
# 实例化flask 对象
app = Flask(__name__) # 实例化对象
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db' # 配置数据库地址 使用dblist
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True #设置数据创建跟踪
db = SQLAlchemy(app) # 将实例化的app对象传入sqlalchemy中
migrate = Migrate(app, db) # 在将app对象和db对象到迁移包中
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
1. 在命令行创建flask 的环境变量
set FLASK_APP = 执行的py文件
2. 在命令行使用
flask db init # 创建迁移的文件夹
3. flask db migrate
创建一个迁移的脚本
4. flask db upgrade
将创建的数据类迁移到数据库中
表结构分开
初始化文件 __init__.py
from flask import Flask # 框架实例
from flask_sqlalchemy import SQLAlchemy # 数据库
from flask_migrate import Migrate # 迁移包
# 实例化flask 对象
app = Flask(__name__) # 实例化对象
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db' # 配置数据库地址 使用dblist
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True #设置数据创建跟踪
db = SQLAlchemy(app) # 将实例化的app对象传入sqlalchemy中
migrate = Migrate(app, db) # 在将app对象和db对象到迁移包中
model.py 文件(数据库的类文件)
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
age = db.Column(db.Integer)
main.py 启动文件
from app import app
from app.models import User # 需要将创建的表模型添加启动文件中
if __name__ == '__main__':
app.run()
# 在进行执行
创建新的表类,需要启动文件中进行导入。在进行加载和迁移(适用表类与实例对象分开的状态)
1.先设置环境变量
set FLASK_APP = 启动文件.py
flask db init # 创建文件(只用创建一次就可以)
flask db migrate # 先加载
flask db upgrade # 在迁移
Flask-Cors
# 跨域
pip install flask-cors
from flask_cors import CORS
CORS(app, resources=r'/*') # 注册CORS, "/*" 允许访问所有api
Flask-session
flask 框架中的session,默认以cookie的方式将session的数据分散保存到客户端中,并非真正意义上的session数据保存,使用flask-session,将session数据指定保存到服务端中(缓存或者数据库中)
可以指定存储的媒介:redis / mongodb / mysql
官方文档:
https://flask-session.readthedocs.io/en/latest/
安装
pip install Flask-Session
保存到数据库mysql
from flask import Flask
from flask_sqlalchemy import SQLAlchemy # 1.导入数据库对象
from flask_session import Session as SessionStore # 1.导入flask_session实例对象
from flask import session # 使用的还是flask中的session对象
app = Flask(__name__)
db = SQLAlchemy() # 2.实例化数据库对象
session_store = SessionStore() # 2.实例化flask_session类
# 3.设置session的配置(使用的mysql作为存储session的媒介的配置如下)
app.config.update({
# 指定数据库配置项
'SQLALCHEMY_DATABASE_URI': 'mysql://root:123456@127.0.0.1:3306/flask?charset=utf8mb4', # SQLAlchemy数据库链接地址
'SQLALCHEMY_TRACK_MODIFICATIONS': False, # 是否追踪对象
'SQLALCHEMY_ECHO': False, # 是否显示sql语句
'DEBUG': True,
'SECRET_KEY': '13213213ASDAQWQWEASD', # 设置session秘钥
# 把session通保存到mysql中以sqlalchemy为媒介进行保存
"SESSION_TYPE": 'sqlalchemy', # 会话类型 redis / sqlalchemy(mysql) 等等方式
'SESSION_SQLALCHEMY': db, # session保存的数据库链接对象(mysql类型的数据库)
'SESSION_SQLALCHEMY_TABLE': 'sessions', # session保存的表名默认是session
'SESSION_PERMANENT': True, # 设置会话期,True关闭浏览器后失效
'SESSION_USE_SIGNER': True, # 是否对发送到浏览器上的session的cookie值进行添加签名,防止修改
'SESSION_KEY_PREFIX': 'session:' # 对存储的session添加标识字符 前缀
})
# 4.数据库初始化
db.init_app(app)
# 4.session类初始化
session_store.init_app(app)
@app.route('/')
def index():
# 1.存储session
session['user_name'] = 'wkx'
session['age'] = 18
# 2.获取session
print(session.get('age'))
print(session.get('user_name'))
# 3.删除session
session.pop('age')
session.pop('user_name')
return 'ok'
if __name__ == '__main__':
# 5.如果使用sqlalchemy作为数据库配置需要进行使用db.create进行数据库创建(在数据库中就会出现一个SESSION_SQLALCHEMY_TABLE设置的表)
with app.app_context():
db.create_all() # 创建数据库
app.run()
1.保存到数据库中后,需要创建数据库
2.删除后,记录还是存储在数据库中
3.如果量大的情况下,不建议使用存储到数据库,速度太慢
保存到redis中
from flask import Flask
from flask_session import Session as SessionStore # 1.导入flask_session
from flask_redis import FlaskRedis # 导入flask_redis对象
from flask import session
app = Flask(__name__)
session_redis = FlaskRedis(config_prefix='REDIS_SESSION') # 实例化redis对象
session_store = SessionStore() # 实例化flask_session类
app.config.update({
# 设置redis的链接url
'REDIS_SESSION_URL': "redis://127.0.0.1:6379/0", # config_prefix='REDIS_SESSION'
'SECRET_KEY': '13213213ASDAQWQWEASD', # 设置session秘钥 必须设置
# 保存到redis中
"SESSION_TYPE": 'redis', # 设置为redis
'SESSION_PERMANENT': True, # 设置会话期,True关闭浏览器后失效
'SESSION_USE_SIGNER': True, # 是否对发送到浏览器上的session的cookie值进行添加签名,防止修改
'SESSION_KEY_PREFIX': 'session:', # 对存储的session添加标识字符 前缀
'SESSION_REDIS': session_redis, # 链接对象(实例化的链接对象)
})
# 2.初始化redis
# 2.初始化session
session_redis.init_app(app)
session_store.init_app(app)
@app.route('/')
def index():
# 1.设置session
session['user'] = 'wkx'
# 2.查询session
print(session.get('user'))
# 3.删除session
session.pop('user')
return 'ok'
if __name__ == '__main__':
app.run()
Flask-redis
安装:为什么:这样使flask app直接接管redis比较方便 将配置卸载app.config中就可以(底层还是pymysql)
pip install flask-redis
https://pypi.org/project/flask-redis/
from flask import Flask
from flask_session import Session as SessionStore # 1.导入flask_session
from flask_redis import FlaskRedis # 导入flask_redis对象
app = Flask(__name__)
app.config.update({
# 'REDIS_URL':redis://:密码@ip:端口/几号库
# 如果没有密码redis://127.0.0.1:6379/0
'REDIS_SESSION_URL': "redis://127.0.0.1:6379/0", # config_prefix='SESSION'
'REDIS_USER_URL': "redis://127.0.0.1:6379/1", # config_prefix='USER'
'REDIS_ORDER_URL': "redis://127.0.0.1:6379/2", # config_prefix='ORDER'
})
# 1.redis因为有16个库的,可以设置多个库进行操作
# 默认链接不同的库中,可以设置redis 的前缀作config_prefix前缀
# 配置信息需要根据设置的前缀取设置链接的库
session_redis = FlaskRedis(config_prefix='REDIS_SESSION')
user_redis = FlaskRedis(config_prefix='REDIS_USER')
order_redis = FlaskRedis(config_prefix='REDIS_ORDER')
# 2.初始化redis
session_redis.init_app(app)
user_redis.init_app(app)
order_redis.init_app(app)
session_store = SessionStore() # 实例化flask_session类
@app.route('/')
def index():
# 直接使用实例对象进行操作即可 select 切换库
# 操作和redis一致 还是调用了redis.Redis对象
session_redis.setnx('age', 100)
user_redis.setnx('user', 100)
order_redis.setnx('order_id', 100)
return 'ok'
if __name__ == '__main__':
app.run()