扩展
蓝图内置扩展 (实现的是路由的拆分)
'''----------- app.py -------------'''
from flask import Flask
from users_views import blue1
from orders_views import blue2 app = Flask(__name__) # 路由注册
app.register_blueprint(blueprint=blue1)
app.register_blueprint(blueprint=blue2) if __name__ == '__main__':
app.run()
''' ------------ users_views.py ---------------'''
from flask import Blueprint
# blue1 的设置(名字,导入的名字,前缀名称)
blue1 = Blueprint("blue1",__name__, url_prefix="/users") # 用blue1设置路由,用前缀名字区分相同名字的路由:http://127.0.0.1:5000/users/
@blue1.route("/")
def index():
return "用户的 Blue 信息" @blue1.route("/user/")
def home():
return "用户信息"
''' ----------- orders_vieews.py ----------'''
from flask import Blueprint
# blue2 的设置(名字,导入的名字,前缀名称)
blue2 = Blueprint("blue2", __name__, url_prefix="/orders") # 用blue2设置路由,用前缀名字区分相同名字的路由:http://127.0.0.1:5000/orders/
@blue2.route("/")
def haha():
return "订单的 blue2 信息" @blue2.route("/orders/")
def ppp():
return "订单信息"
静态文件路径
from flask import Flask
from users_views import blue1
from orders_views import blue2
# 静态文件路径配置。static_folder='news/static' 是配置新的静态文件的路径
app = Flask(__name__,static_folder='news/static') # 路由注册
app.register_blueprint(blueprint=blue1)
app.register_blueprint(blueprint=blue2)
终端命令启动项目插件扩展:
- 实现:flask-script
- 安装:pip install flask-script
- 作用:实现命令键入的方式 启动项目
- 使用:在终端键入:python app.py runserver
- 查看帮助文档: python app.py runserver --help
- 设置指定端口: python app.py runserver -h ip地址 -p 端口号
- 设置自动重启: python app.py runserver -r
- 设置调试模式: python app.py runserver -d
- shell脚本调试: python app.py shell 在终端内添加model数据
- 配置:
from flask import Flask
from flask_script import Manager app = Flask(__name__)
# 配置flask-script
manager = Manager(app=app) @app.route('/')
def hello_world():
return 'Hello World!' # 使用flask-script
if __name__ == '__main__':
manager.run() flask-script
对象模型迁移数据库表扩展:
- 实现:flask-migrate
- 安装:pip install flask-migrate -i http://pypi.douban.com/simple
- 作用:迁移,可以自动将模型转变成数据库中的表
- 配置:
- 在extension.py扩展文件中绑定app和db。详见下面代码块 ;创建一个Migrate对象,传递app和db进去
- 然后,在manage.py启动文件的manager对象上添加指令:manager.add_command("db",MigrateCommand)
- 使用:
- 首次使用需要初始化: python manage.py db init
- 如果模型有变更,生成迁移文件:python manage.py db migrate
- 将迁移文件映射到数据库中: python manage.py db upgrade
- 后悔返回,回滚操作: python manage.py db downgrade
- extension.py
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy()
# 扩展文件添加配置信息。创建一个Migrate对象。
migate = Migrate() # 应用一个函数,使用函数传参数将app导入初始化
def init_ext(app):
db.init_app(app)
migate.init_app(app,db) # 将app和db以参数的形式传递进去。注册上
- manage.py
# 注册迁移工具命令行
manager.add_command("db",MigrateCommand) if __name__ == '__main__':
manager.run()
- 未拆分写法
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from app import create_app, db app = create_app()
manager = Manager(app=app) # 创建迁移工具实例
migrate = Migrate()
migrate.init_app(app=app,db=db) # 注册迁移工具命令行
manager.add_command("db",MigrateCommand) if __name__ == '__main__':
manager.run()
数据库模型和对象关系扩展:
- 实现:SQLAlchemy; pymysql驱动
- 安装:pip install flask-sqlalchemy ;pip install pymysql
- 作用:ORM(Object Relational Mapping) 对象关系映射。将数据库转为面向对象的操作,通过操作对象就可实现对数据的CRUD
- 配置:
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) # 配置连接sqlite数据库的指定信息。SQLite数据库连接不需要额外驱动,也不需要用户名和密码
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///hello.sqlite'
# 设False为更好的兼容性,禁止对象追踪修改
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) # 配置连接mysql数据库的指定信息。dialect+driver://username:password@host:port/database
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:guoyapeng@localhost:3306/FlaskModel'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app) if __name__ == '__main__':
app.run()
- 使用:下面链接文件中的 模型板块
缓存技术cache扩展库插件:
- 实现:flask_caching
- 安装:pip install flask-caching
- 作用:
- 减少磁盘IO可以大幅度提升服务器性能。
- 数据库IO操作的是web应⽤性能的瓶颈。为了提⾼访问效率,应尽可能减少数据库的操作。
- 可以将经常访问的数据缓存起来,再次使⽤用时直接从缓存中获取,而不是每次都操作数据库。
- 字段:
from flask_caching import Cache cache = Cache()
cache.init_app(app=app, config={'CACHE_TYPE': 'simple'})
CACHE_REDIS_URL # 连接到Redis服务器的URL。一键配置示例
cache = Cache(config={
"CACHE_TYPE": "redis",
"CACHE_REDIS_URL":"redis://:localhost@127.0.0.1:6379/1",}) # 以下参数是所有的类型共有的
CACHE_NO_NULL_WARNING = "warning" # null类型时的警告消息
CACHE_ARGS = [] # 在缓存类实例化过程中解包和传递的可选列表,用来配置相关后端的额外的参数
CACHE_OPTIONS = {} # 可选字典,在缓存类实例化期间传递,也是用来配置相关后端的额外的键值对参数
CACHE_DEFAULT_TIMEOUT # 默认过期/超时时间,单位为秒
CACHE_THRESHOLD # 缓存的最大条目数 CACHE_TYPE: # 设置缓存的类型
CACHE_TYPE = null # 默认的缓存类型,无缓存
CACHE_TYPE = 'simple' # 使用本地python字典进行存储,非线程安全
CACHE_TYPE = 'filesystem' # 使用文件系统来存储缓存的值
CACHE_TYPE = 'memcached' # 使用memcached服务器缓存
CACHE_TYPE = 'redis' # 使用redis作为缓存
CACHE_TYPE = 'filesystem' # 使用文件系统来存储缓存的值
CACHE_DIR = "" # 文件目录 CACHE_TYPE = 'memcached' # 使用memcached服务器缓存
CACHE_KEY_PREFIX # 设置cache_key的前缀
CAHCE_MEMCACHED_SERVERS # 服务器地址的列表或元组
CACHE_MEMCACHED_USERNAME # 用户名
CACHE_MEMCACHED_PASSWORD # 密码 CACHE_TYPE = 'redis' # 使用redis作为缓存
CACHE_KEY_PREFIX # 设置cache_key的前缀
CACHE_REDIS_HOST # redis地址
CACHE_REDIS_PORT # redis端口
CACHE_REDIS_PASSWORD # redis密码
CACHE_REDIS_DB # 使用哪个数据库
- 配置
- manage.py
from flask_script import Manager
from app import create_app app = create_app()
manager = Manager(app=app) if __name__ == '__main__':
manager.run()
- app/__init__.py
from flask import Flask
from app import views, ext def create_app():
app = Flask(__name__)
# 注册缓存配置
ext.init_cache(app)
# 注册路由
app.register_blueprint(views.bp)
return app
- app/ext.py
from flask_caching import Cache cache = Cache() def init_cache(app): # CACHE_TYPE = 'redis' 使用redis作为缓存
# CACHE_KEY_PREFIX 设置cache_key的前缀。不设置表示默认
# CACHE_REDIS_HOST redis地址
# CACHE_REDIS_PORT redis端口
# CACHE_REDIS_PASSWORD redis密码。没密码就不用设置
# CACHE_REDIS_DB 使用哪个数据库,不设置表示随机 app.config["CACHE_TYPE"] = "redis"
app.config["CACHE_REDIS_HOST"] = "127.0.0.1"
app.config["CACHE_REDIS_PORT"] = 6379
# 设置缓存到app上
cache.init_app(app=app)
- 使用
- movies/views.py
from time import sleep
from app.ext import cache @user_blue.route("/learn/")
@cache.cached(60) # 设置缓存,60秒有效
def learn():
print("开始学习")
sleep(10)
print("结束学习")
return "缓存技术,提高学习时间"
会话技术session扩展库插件:
- 实现:flask_session
- 作用:实现http的长链接,用会话技术为了数据可以跨请求使用,让服务器识别客户端
- 安装:pip install flask-session
- 配置:
import datetime
from flask import Flask
from flask_session import Session
from app import views def create_app(): app = Flask(__name__) # 为sesson设置一个密钥key值。两种方式,推荐第二种
# app.secret_key = 'asdfghjkl'
app.config['SECRET_KEY'] = 'd53a40dae292df9d409ef64e4a04905d' # flssk-session 扩展配置
# 指定 flask-session 扩展将 session 数据持久化到 redis 中
app.config['SESSION_TYPE'] = 'redis' # 指定 flask-session 存储在 redis 中的 session id的前缀
app.config['SESSION_KEY_PREFIX'] = 'flask:session' # 自定义 session 过期时间
app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=7) # 创建 flask-session 的 Session 对象
sess = Session() # 将 flask-session 扩展初始化,跟app建立链接
sess.init_app(app=app) app.register_blueprint(views.bp) # 注册路由
return app
- 使用: 以下链接中的 session会话 模块
管理⽤户登录登出扩展库插件:
- 实现:flask-login
- 安装:pip install flask-login
- 作用:是一个专门用来管理用户登录退出的扩展库
- 步骤:
- 1. 在extension.py中 app上注册flask-login扩展,指定登陆页面。如下两行代码
- 2. 在model.py中 在登陆对象(User)中继承 UserMixin类,提供便捷的功能
- 3. 在views.py中 增加load_user回调函数,导入扩展文件包加装饰器@login_manager.user_loader。
- 供flask-login扩展在内部加载当前登陆的用户对象。flask-login默认通过user id的方式,调用load_user函数,获得用户对象
- 4. 登陆成功后,调用login_user(user)将登陆成功的对象绑定到session中
- 5. 使用lagin_required装饰器,保护访问受限的视图函数
- 配置:
- manage.py 注册
# 添加扩展
from flask import Flask
from flask.ext.login import LoginManager app = Flask(__name__) # 1.实例化login_manager
login_manager = LoginManager()
# 2.将login_manager与app绑定
login_manager.init_app(app)
# 3.设置登录视图名称。如果未登录用户请求只有登录用户才能访问的视图,则重定向到这个设置的登录视图。
login_manager.login_view = 'blue.login' # 4.如果未设置登录视图,则直接返回401错误。设置登录错误信息
login_manager.login_message = '请登录!'
- models.py 继承
from flask_login import UserMixin
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy()
# 让User继承自UserMixin。
class User(UserMixin,db.Model):
__tablename__= "users"
id = db.Column(db.Integer,primary_key=True)
username = db.Column(db.String(16),unique=True,nullable=False)
password = db.Column(db.String(256),unique=True,nullable=False)
- views.py 初始化
# 告诉ext.py中login_manager的用户是从哪来的。用户加载的地方
@login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
- 使用
"""
状态切换:
login_user # 登录
4 logout_user # 退出登录 路由保护:
7 login_required # 保护需要登录才能访问的路路由 当前用户:
10 current_user # 哪⾥都可以使⽤(在模板中不需要分配) 实现回调:
13 @login_manager.user_loader
14 def load_user(uid):
15 return User.query.get(uid)
"""
#属性 is_authenticated
#当用户登录成功后,该属性为True。 #属性 is_active
#如果该用户账号已被激活,且该用户已登录成功,则此属性为True。 #属性 is_anonymous
#是否为匿名用户(未登录用户)。 #方法 get_id()
#每个用户都必须有一个唯一的标识符作为ID,该方法可以返回当前用户的ID,这里ID必须是Unicode。
<body> 9 {# 当前用户:current_user,属性:is_authenticated 当前用户登录成功后该属性为True。 #}
10 {# 判断用户是否登陆,如果登陆显示:用户名、注销、用户主页、关于网站。如果没有登陆显示:请登录、用户主页、关于网站 #}
{% if current_user.is_authenticated %}
当前登陆用户为:{{ current_user.username }}<a href="{{ url_for("blue.logout") }}">注销</a>
{% else %}
<a href="{{ url_for("blue.login") }}">请登录</a>
{% endif %}
<a href="{{ url_for("blue.home") }}">用户主页</a>
<a href="{{ url_for("blue.about") }}">关于网站</a> </body>
- models.py
from flask_login import UserMixin
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class User(UserMixin,db.Model):
__tablename__= "users"
id = db.Column(db.Integer,primary_key=True)
username = db.Column(db.String(16),unique=True,nullable=False)
password = db.Column(db.String(256),unique=True,nullable=False)
- views.py
from flask import Blueprint, render_template, request, redirect, url_for, flash
from flask_login import login_user, logout_user, login_required
from werkzeug.security import generate_password_hash, check_password_hash
from app.ext import login_manager
from app.models import User, db bp = Blueprint('blue', __name__) @bp.route('/register/', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
# 处理注册逻辑。 1、检查两次输入的密码是否相等; 2、检查用户名是否重复
username = request.form.get('username')
password = request.form.get('password')
re_password = request.form.get('re_password') # 检查两次输入的密码是否相等
if password != re_password:
return render_template('register.html', msg='两次输入密码不一致', username=username)
# 查询数据库中是否有重复的用户名。 .count() 获得查询语句匹配到的行数
if User.query.filter_by(username=username).count() > 0:
return render_template('register.html', msg='用户名重复', username=username) # 对 password 进行加密。进行存储准备
password_hash = generate_password_hash(password)
user = User()
user.username = username
user.password = password_hash
# 对新注册的用户进行存储
db.session.add(user)
db.session.commit() # flash 闪现消息,可以跨请求传递消息,不跨请求时也可以使用
# 本质上:内部会把消息保存到 session中,在下一个请求中通过session获取
"""
在 html 中使用
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}
"""
flash('注册成功,请登录')
return redirect(url_for('blue.login'))
return render_template('register.html') @bp.route("/login/",methods=["POST","GET"])
def login():
if request.method == "POST":
# 处理登陆业务
username = request.form.get("username")
password = request.form.get("password") user = User.query.filter_by(username=username).first()
if user is None:
return render_template("login.html",msg="用户或密码错误",username=username)
if check_password_hash(user.password,password): # 登陆成功以后需要将登陆状态保存到session中session['uid']=user.id,使用flask-login的login_user()来完成
login_user(user) # 即使是post请求,也可以用args获取跳转链接next的参数值,http://127.0.0.1:5000/login/?next=%2Fhome%2F
next_url = request.args.get("next")
# 如果存在 next 跳转参数,则跳转到 next 页面;否则调转到首页
return redirect(next_url or url_for("blue.index"))
else:
return render_template("login.html", msg="用户或密码错误", username=username)
return render_template("login.html") # 保护页面。需要配置默认调转页面
# 使用装饰器:@login_required 实现:只有登陆的用户,点击home时页面才会看到信息;没有登陆的用户点击会被跳转到登陆页面
@bp.route("/home/")
@login_required
def home():
return "home" # 登出操作。用 flask-login的logout_user()自动完成登出时session的清理工作
@bp.route("/logout/")
def logout():
logout_user()
return redirect(url_for("blue.index")) # 告诉ext.py中login_manager的用户是从哪来的。用户加载的地方
@login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id) @bp.route("/about/")
def about():
return "about" @bp.route('/')
def index():
return render_template('index.html')
views.py
表单验证模块扩展库插件:
- 实现:flask-wtf
- 作用:是flask框架的表单验证模块。可以很方便生成表单、验证表单的数据。CSRF、字段校验等功能。
- 安装:pip install flask-wtf
- 注意:如果使用form提交的话,自动将form.py中的属性和html中的同名元素匹配,html中需要注明 {{ form.csrf_token }}
form.py中的 username = StringField(...)匹配 .html中的 <input name="username">
- 字段
SelectField:下拉框内容在 form 表单类初始化时即确定。运行中修改不生效(验证时会出错)
QuerySelectField:下拉框内容可以动态从数据库中获取,query_factory指定查询接口
- 配置:
- form.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Length, EqualTo class RegisterForm(FlaskForm):
# 定义页面中显示的字段标签。username是StringField类型
username = StringField(
# label标签 显示:"用户名"
label='用户名',
# 验证器:列表类型。
validators=[
# DataRequired 必填信息
DataRequired(message='用户名为必填')
]
)
password = PasswordField(
label='密码',
validators=[
DataRequired(message='密码为必填'),
# 长度验证(最小2,最长4)
Length(min=2, max=4, message='密码长度为 2 ~ 4'),
]
)
password_confirm = PasswordField(
label='重复密码',
validators=[
# EqualTo验证和谁相等(要比较的变量)
EqualTo('password', message='两次输入的密码必须一致'),
]
) class LoginForm(FlaskForm):
username = StringField(
label='用户名',
# 默认值:空
default='',
validators=[
DataRequired(message='用户名为必填')
]
)
password = PasswordField(
label='密码',
validators=[
DataRequired(message='密码为必填'),
]
)
- 使用:
- views.py
from flask import Blueprint, render_template, request, redirect, url_for
from flask_login import login_user
from werkzeug.security import generate_password_hash, check_password_hash
from app.ext import login_manager
from app.form import RegisterForm, LoginForm
from app.models import User, db bp = Blueprint('blue', __name__) @bp.route('/form/register/', methods=['GET', 'POST'])
def register_form():
form = RegisterForm()
# 普通写法:
# if request.method == 'POST':
# username = request.form.get('username') # form写法
# validate_on_submit 内部做了三件事
# 1、判断 request.method 是否为 POST, PUT, PATCH, DELETE
# 相当于 if request.method == 'POST'
# 2、将表单中的同名元素自动绑定到form中的同名属性中
# 相当于 username = request.form.get('username')
# form.username = username
# 3、验证表单数据,根据表单字段中定一个的 validators
if form.validate_on_submit():
# 前端数据在form验证通过后,从form获取前端传入的数据
print(form.data)
username = form.username.data
password = form.password.data password_hash = generate_password_hash(password) user = User()
user.username = username
user.password = password_hash db.session.add(user)
db.session.commit()
return redirect(url_for('blue.login_form'))
return render_template('register_form.html', form=form) # 返回form对象数据 @bp.route('/form/login/', methods=['POST', 'GET'])
def login_form():
form = LoginForm() # validate_on_submit 内部做了三件事
# 1、判断 request.method是否为POST, PUT, PATCH, DELETE
# 相当于 if request.method=='POST'
# 2、将表单中的同名元素自动绑定到form中的同名属性中
# 相当于 username = request.form.get('username')
# form.username = username
# 3、验证表单数据,根据表单字段中定一个的 validators
if form.validate_on_submit():
username = form.username.data
password = form.password.data # 先根据用户名查询数据库中是否有该数据
user = User.query.filter_by(username=username).first() if user is None:
# 如果查询的对象不存在。手工向form.username.errors追加一条错误信息,通过form显示到前端页面
form.username.errors.append('用户或密码错误')
return render_template('login_form.html', form=form) if check_password_hash(user.password, password):
# 如果密码验证通过。使用flask-login的login_user()完成保存登陆状态的工作
# 登录成功以后,需要将登录状态保存到session中,比如:session['uid']=user.id
login_user(user) # 获得跳转连接,如果url中存在next跳转参数,则跳转到next页面,否则跳转到首页
# 通过args获取post请求中的URL的next参数信息
next_url = request.args.get('next')
return redirect(next_url or url_for('blue.index'))
else:
form.password.errors.append('用户或密码错误')
return render_template('login_form.html', form=form)
return render_template('login_form.html', form=form) @bp.route("/form/index/",methods=['POST','GET'])
def index():
return render_template("index.html") @login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
# 修改资源
@app.route('/article/<article_id>/change/', methods=['POST', 'GET'])
def article_change(article_id):
article = Article.query.get(article_id)
# 根据 数据库中查询到的数据 创建 Form 对象
# ArticleForm 内部会 将 article 对象的同名属性设置到 ArticleForm 的同名属性上
# form.title = article.title
# form.content = article.content
# form.title.data
form = ArticleForm(obj=article)
if form.validate_on_submit():
# 使用表单对象的 populate_obj 方法,用已验证表单的内容来填充 Article 对象
# 将表单中提交过来的内容,再次反向绑定form上去
# article.title = form.title.data
# article.content = form.content.data
form.populate_obj(article)
db.session.commit() flash('文章保存成功')
return redirect(url_for('blue.article_list'))
return render_template('article-change.html', form=form)
修改资源
- login_form.html
<body>
<form action="{{ url_for("blue.index") }}" method="post">
{# <跨域访问></防跨域访问> #}
{{ form.csrf_token }}
{# 登陆验证失败后: <重新显示输入的信息> </返回错误原因> #}
用户名:<input name="username" type="text" value="{{ form.username.data }}">{{ form.username.errors }}
密码:<input name="password" type="password" value="">{{ form.password.errors }}
<input type="submit" value="submit">
</form>
</body>
- register.html
<body>
<form action="" method="post">
{# <csrf防跨域访问></csrf防跨域访问> #}
{{ form.csrf_token }}
{# flask-wtf 写法 #}
{{ form.username.label }} {{ form.username() }} {{ form.username.errors }}
{{ form.password.label }} {{ form.password }} {{ form.password.errors }}
{{ form.password_confirm.label }} {{ form.password_confirm }} {{ form.password_confirm.errors }}
<input type="submit" value="submit">
</form>
</body>
缓存技术
方法
"""
cache.cached:装饰器,装饰无参数函数,使得该函数结果可以缓存
参数:
timeout: 超时时间
key_prefix: 设置该函数的标志
unless: 设置是否启用缓存,如果为True,不启用缓存
forced_update: 设置缓存是否实时更新,如果为True,无论是否过期都将更新缓存
query_string: 为True时,缓存键是先将参数排序然后哈希的结果 cache.memoize:装饰器,装饰有参数函数,使得该函数结果可以缓存
参数:
make_name:设置函数的标志,如果没有就使用装饰的函数
其他参数同cached cache.delete_memoized:删除缓存
参数:
func_name:缓存函数的引用
*args:函数参数
"""
# cache.clear() # 清除缓存所有的缓存,这个操作需要慎重
# cache.get(key) # 获取一个键的值,如果值是json格式会自动转化成字典
# cache.set(key,value,timeout) #设置一个键值,value可以是字典,会自动转化json格式的字符串
# cache.add(key, value, timeout=None) #设置一个键值,如果存在就pass,注意和set的区别
# cache.delete(key) #删除键
流程
使用
- app/views.py
import random
import time
from flask import Blueprint
from app.ext import cache bp = Blueprint("blue",__name__) # 缓存视图函数 设置缓存。过期时间10秒
@bp.route("/cache_views/")
@cache.cached(timeout=10)
def cache_views():
"""
当通过 cache.cached 缓存视图函数时,
在超时之前(timeout<10)访问此视图函数,会先去去缓存中查找,返回缓存中的数据。
在超时之后(timeout>10)访问此视图函数,会去缓存中查找,查不到再去数据库中查找,后保存在缓存中并返回数据。
:return: 例如:网站首页,不经常变化的话,可以将其存到缓存中
"""
now = time.time()
return str(now) # 缓存普通函数(单独缓存某个函数,提供更好的复用性)
# 推荐指定key_prefix,缓存key的前缀。否则key为调⽤的视图函数所在的路由
@cache.cached(timeout=30, key_prefix='random_list')
def random_list(): # 随机提取十个数字
return [random.randint(0, 100) for _ in range(10)] @bp.route('/random_view/')
def random_view():
list0 = random_list() # 获取缓存中的十个数据
list1 = ",".join(map(str,list0))
list2 = list1 + "------>" + str(random.randint(0, 100))
return list2 # 缓存带参函数
@cache.memoize(timeout=30,make_name="random_parm")
def random_parm(arg1, arg2):
return arg1 + arg2 + random.randint(0,10)
# 根据参数值 随机获取数值。参数不同 获得的随机数不同,且互不影响
# http://127.0.0.1:5000/random_args/1/3/ 结果:4----->73
# http://127.0.0.1:5000/random_args/1/2/ 结果:6----->48
@bp.route("/random_args/<int:arg1>/<int:arg2>/")
def random_args(arg1,arg2):
return str(random_parm(arg1,arg2)) + "----->" + str(random.randint(0,100))
# 清理缓存。cache.delete(函数名,此函数参数,此函数参数)
@bp.route("/delete/<int:arg1>/<int:arg2>")
def delete(arg1,arg2):
cache.delete(random_parm,arg1,arg2)
return "ok" # 缓存对象(键值对)。cache.set('键', '值', 过期时间)
@bp.route("/set_cache/")
def set_cache():
cache.set('name', '老王', timeout=30)
cache.set('persion', {'name': '晓黎', 'age': 18}, timeout=30)
cache.set('lst', [1, 2, 3, 4], timeout=30)
# 模拟登录成功后,把用户身份信息保存到 session
session_id = ''
cache.set(session_id, {'user_id': 123456}, timeout=1800) print(cache.get('name'))
print(cache.get('persion'))
print(cache.get('lst'))
# 模拟 根据 session_id 获取用户的身份信息
print(cache.get(session_id)) return "ok"
会话技术(cookie)
出现原因:HTTP是无状态协议,使用的短连接,请求周期非常短。使用会话技术为了数据可以跨请求使用,让服务器识别客户端
Cookie:Cookie客户端会话技术,数据都存储在浏览器中,默认携带本网站的所有Cookie。缺点:明文传输不安全
Cookie以key-value存储,支持过期,默认关闭浏览器即失效;不能跨浏览器,不能跨域名访问
- manage.py
from flask_script import Manager
from app import create_app app = create_app()
manager = Manager(app=app) if __name__ == '__main__':
manager.run()
- app/__init__.py
from flask import Flask
from app import views def create_app():
app = Flask(__name__) # 实例化 Flask对象
app.register_blueprint(views.bp) # 将蓝图注册到app上
return app # 返回出去 Flask实例
- app/views.py
from flask import Blueprint, request, render_template, make_response, redirect, url_for, abort # 用蓝图管理路由,规划url。参数("蓝图名字",__name__)
# 蓝图必须了管理的视图在一个文件中,不然不能使用
bp = Blueprint("blue",__name__) @bp.route('/index')
def index():
username = request.cookies.get('username','游客')
return render_template("index.html",username= username) @bp.route('/login/',methods=['GET','POST'])
def login():
if request.method == "POST":
username = request.form.get('username')
# 模拟登陆。使用redirect 来获取响应对象。
response = redirect(url_for('blue.index'))
# 通过response对象设置cookie
response.set_cookie('username',username)
return response
# render_template(模版名称,**context) **context是需要传递到模版中的 变量
return render_template('login.html') @bp.route('/logout/')
def logout():
# 模拟登陆,使用redirect 来获取响应对象。
response = redirect(url_for('blue.index'))
# 删除cookie
response.delete_cookie('username')
return response
- app/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h2>欢迎:{{ username }}</h2>
<form action="{{ url_for('blue.logout')}}" method="get">
<input type="submit" value="登出">
</form>
</body>
</html>
- app/templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="{{ url_for('blue.login')}}" method="post">
<input type="text" name="username" value="" placeholder="请输入用户名">
<input type="submit" value="登录">
</form>
</body>
</html>
会话技术(session)
Session:服务端会话技术,数据都存储在服务端
1、当浏览器第一次访问 web 服务器时,web 服务器会为此浏览器生成一个 session,为这个 session 创建一个唯一的 session_id;
2、在服务器返回请求时,会向浏览器设置 cookies,cookies 中是 key-value 存储reseponse.set_cookies('session_id', session_id, expire=)
3、浏览器再次访问此 web 服务器时,会在请求中带上 cookies 信息,即:session_id: dsfksdlfj232wrwdsf
4、当 web 服务器在次接收到浏览器请求时,会从请求的 cookies 中提取 session_id 的值,
然后根据 session_id 的值,查找到与当前浏览器匹配的 session(比如:从数据库查询等)
绘画特性:依赖于Cookie,以key-value存储、相对安全、不能跨网站,不能跨域名、支持过期默认31天 -> 设置:session.permanent = True
- manage.py
from flask_script import Manager
from app import create_app app = create_app()
manager = Manager(app=app) if __name__ == '__main__':
manager.run()
- app/__init__.py
import datetime
from flask import Flask
from flask_session import Session
from app import views def create_app(): app = Flask(__name__) # 为sesson设置一个密钥key值。两种方式,推荐第二种
# app.secret_key = 'asdfghjkl'
app.config['SECRET_KEY'] = 'd53a40dae292df9d409ef64e4a04905d' # flssk-session 扩展配置
# 指定 flask-session 扩展将 session 数据持久化到 redis 中
app.config['SESSION_TYPE'] = 'redis' # 指定 flask-session 存储在 redis 中的 session id的前缀
app.config['SESSION_KEY_PREFIX'] = 'flask:session' # 自定义 session 过期时间
app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=7) # 创建 flask-session 的 Session 对象
sess = Session() # 将 flask-session 扩展初始化,跟app建立链接
sess.init_app(app=app) app.register_blueprint(views.bp) # 注册路由
return app
- app/views.py
from flask import Blueprint, render_template, redirect, url_for, request, session # Blueprint: 第一个参数为蓝图自定义名称,第二个参数是 Blueprint 对views.py 导入时需要的名称。
bp = Blueprint('blue',__name__)
"""
在 flask 项目中使用 session
1. 为 flask 对象(app)设置secrt key
2、在任何视图函数中都可以像使用字典一样操作 session
session['username'] = 'jack' 向session中增加一个 键值对
session.get('username') 从session中根据key获取value
session.pop('username') 从session中删除指定的key
"""
@bp.route('/index/')
def index():
# session.get 从 session 中根据key获取对用的值。可以像字典一样操作
username = session.get('username','游客')
return render_template('index.html',username=username) @bp.route('/login/',methods=["POST","GET"])
def login():
if request.method == 'POST':
username = request.form.get('username')
session['username'] = username
return redirect(url_for('blue.index'))
return render_template('login.html') @bp.route('/logout/')
def logout():
session.pop('username')
return redirect(url_for('blue.index'))
# 设置退出,
@app.route('/logout/')
def logout():
response = Response('退出成功')
response.delete_cookie('session') # 删除session中的session参数
session.pop['username'] # 删除session中的username参数值 推荐
del session['username'] # 删除session中的username参数值 不存在,会报错
return response
- app/templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="{{ url_for('blue.login')}}" method="post">
<input type="text" name="username" value="" placeholder="请输入用户名">
<input type="submit" value="登录">
</form>
</body>
</html>
- app/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>欢迎:{{ username }}</h2>
<form action="{{ url_for('blue.logout')}}" method="get">
<input type="submit" value="登出">
</form>
</body>
</html>