10-flask框架-数据库迁移/session存储/faker模块/配置项写法
-
-
更好的解决办法是使用数据库迁移框架,它可以追踪数据库模式的变化,然后把变动应用到数据库中。
-
在Flask中可以使用Flask-Migrate扩展,来实现数据迁移。并且集成到Flask-Script中,所有操作通过命令就能完成。
-
为了导出数据库迁移命令,Flask-Migrate提供了一个MigrateCommand类,可以附加到flask-script的manager对象上。
首先要在虚拟环境中安装Flask-Migrate
pip install flask-migrate
代码 manage.py文件内容:
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) class Config(object): DEBUG = True # 数据库连接配置 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" # 动态追踪修改设置,如未设置只会提示警告 SQLALCHEMY_TRACK_MODIFICATIONS = True # 查询时会显示原始SQL语句 SQLALCHEMY_ECHO = True app.config.from_object(Config) db = SQLAlchemy(app=app) # 初始化数据迁移工具 # 初始化完成以后,由Migrate会在系统终端下创建 flask db 的迁移命令 from flask_migrate import Migrate migrate = Migrate() migrate.init_app(app=app,db=db) """模型类定义""" # 多对多关系表 achievement = db.Table( 'db_achievement', db.Column('id', db.Integer, primary_key=True), db.Column('student_id', db.Integer, db.ForeignKey('db_students.id')), db.Column('course_id', db.Integer, db.ForeignKey('db_course.id')), ) class Student(db.Model): """学生信息模型""" __tablename__ = "db_students" id = db.Column(db.Integer, primary_key=True,comment="主键") name = db.Column(db.String(15), comment="姓名") age = db.Column(db.SmallInteger, comment="年龄") sex = db.Column(db.Boolean, default=True, comment="性别") email = db.Column(db.String(128), comment="邮箱地址") money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") course_list = db.relationship("Course",secondary=achievement, backref="student_list", lazy="dynamic") def __repr__(self): return f"{self.name}<Student>" class Course(db.Model): """课程数据模型""" __tablename__ = "db_course" id = db.Column(db.Integer, primary_key=True, comment="主键") name = db.Column(db.String(64), unique=True, comment="课程") price = db.Column(db.Numeric(7, 2)) cover = db.Column(db.String(255), comment="封面图片") desc = db.Column(db.String(255), comment="课程介绍") def __repr__(self): return f'{self.name}<Course>' @app.route("/") def index(): return "ok" if __name__ == '__main__': app.run()
# 切换到项目根目录下, cd ~/Desktop/flaskdemo # 设置flask项目的启动脚本位置 # 新版本的flask1.1,会在系统终端下提供一个类似django-admin的终端命令工具, 可以实现类似 flask_scipt 的功能 export FLASK_APP=manage.py # flask run 启动flask项目 # 数据库迁移初始化,这个命令会在当前项目根目录下创建migrations文件夹,所有数据表相关的迁移文件都放在里面。 flask db init
-
-
upgrade():函数把迁移中的改动应用到数据库中。
-
downgrade():函数则将改动删除。
-
-
自动创建的迁移脚本会根据模型定义和数据库当前状态的差异,生成upgrade()和downgrade()函数的内容。
-
对比不一定完全正确,有可能会遗漏一些细节,需要进行检查
# 根据flask项目的模型生成迁移文件 flask db migrate -m 'initial migration' # 这里等同于django里面的 makemigrations,生成迁移版本文件 # 完成2件事情: # 1. 在migrations/versions生成一个数据库迁移文件 # 2. 如果是首次生成迁移文件的项目,则迁移工具还会在数据库创建一个记录数据库版本的version表
# 从migations目录下的versions中根据迁移文件upgrade方法把数据表的结构同步到数据库中。 flask db upgrade
# 从migations目录下的versions中根据迁移文件downgrade把数据表的结构同步到数据库中。 flask db downgrade
可以根据history命令找到版本号,然后传给downgrade命令:
flask db history
输出格式:<base> -> 版本号 (head), initial migration
flask db downgrade # 默认返回上一个版本 flask db downgrade 版本号 # 回滚到指定版本号对应的版本 flask db upgrade 版本号 # 升级到指定版本号对应的版本
数据迁移的步骤:
1. 初始化数据迁移的目录 export FLASK_APP=manage.py flask db init 2. 数据库的数据迁移版本初始化 flask db migrate -m 'initial migration' 3. 升级版本[创建表/创建字段/修改字段] flask db upgrade 4. 降级版本[删除表/删除字段/恢复字段] flask db downgrade
文档: https://faker.readthedocs.io/en/master/locales/zh_CN.html
批量生成测试数据: https://github.com/joke2k/faker
pip install faker -i https://pypi.douban.com/simple
代码:
1 from flask import Flask 2 from flask_sqlalchemy import SQLAlchemy 3 4 app = Flask(__name__) 5 6 class Config(object): 7 DEBUG = True 8 # 数据库连接配置 9 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" 10 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" 11 # 动态追踪修改设置,如未设置只会提示警告 12 SQLALCHEMY_TRACK_MODIFICATIONS = True 13 # 查询时会显示原始SQL语句 14 SQLALCHEMY_ECHO = True 15 16 app.config.from_object(Config) 17 db = SQLAlchemy(app=app) 18 19 class Student(db.Model): 20 """学生信息模型""" 21 __tablename__ = "db_students" 22 id = db.Column(db.Integer, primary_key=True,comment="主键") 23 name = db.Column(db.String(15), comment="姓名") 24 age = db.Column(db.SmallInteger, comment="年龄") 25 sex = db.Column(db.Boolean, default=True, comment="性别") 26 email = db.Column(db.String(128), comment="邮箱地址") 27 money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包") 28 29 def __repr__(self): 30 return f"{self.name}<Student>" 31 32 from flask_script import Command,Manager,Option 33 34 manage = Manager() 35 manage.app = app 36 37 # 自定义批量生成学生 38 import random 39 from faker import Faker 40 class FakerStudentCommand(Command): 41 """生成测试学生信息""" 42 Name = "student" 43 option_list = ( 44 Option("-n","--num",dest="num", type=int), 45 ) 46 47 def run(self,num): 48 faker = Faker(locale="ZH_CN") 49 for i in range(num): 50 sex = bool( random.randint(0,1) ) 51 student = Student( 52 name= faker.name_male() if sex else faker.name_female(), 53 age=random.randint(15,60), 54 sex=sex, 55 email=faker.free_email(), 56 money= float( random.randint(100,100000) / 100 ), 57 ) 58 db.session.add(student) 59 # 在循环外面统一提交 60 db.session.commit() 61 62 manage.add_command(FakerStudentCommand.Name, FakerStudentCommand) 63 64 @app.route("/") 65 def index(): 66 return "ok" 67 68 if __name__ == '__main__': 69 manage.run()
session如如果不设置默认存储到系统的文件中,通过此模块允许设置session到指定存储的空间中, 文档:
pip install flask-session
使用session之前,必须配置一下配置项:
SECRET_KEY = "*(%#4sxcz(^(#$#8423" # session秘钥
只要配置项:
# 把session通过SQLAlchmey保存到mysql中 SESSION_TYPE = "sqlalchemy" # session类型为sqlalchemy SESSION_SQLALCHEMY = db # SQLAlchemy对象 SESSION_SQLALCHEMY_TABLE = 'db_session' # session要保存的表名称 SESSION_PERMANENT = True # 如果设置为True,则关闭浏览器session就失效 SESSION_USE_SIGNER = False # 是否对发送到浏览器上session的cookie值进行加密 SESSION_KEY_PREFIX = "session:" # sessionID的前缀,默认就是 session:
1 from flask import Flask 2 from flask_sqlalchemy import SQLAlchemy 3 from flask_session import Session 4 app = Flask(__name__) 5 db = SQLAlchemy() 6 session_store = Session(app) 7 8 class Config(object): 9 DEBUG = True 10 SECRET_KEY = "*(%#4sxcz(^(#$#8423" # session秘钥 11 # 数据库连接配置 12 # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4" 13 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" 14 # 动态追踪修改设置,如未设置只会提示警告 15 SQLALCHEMY_TRACK_MODIFICATIONS = True 16 # 查询时会显示原始SQL语句 17 SQLALCHEMY_ECHO = False 18 # 把session通过SQLAlchmey保存到mysql中 19 SESSION_TYPE = "sqlalchemy" # session类型为sqlalchemy 20 SESSION_SQLALCHEMY = db # SQLAlchemy对象 21 SESSION_SQLALCHEMY_TABLE = 'db_session' # session要保存的表名称 22 SESSION_PERMANENT = True # 如果设置为True,则关闭浏览器session就失效 23 SESSION_USE_SIGNER = False # 是否对发送到浏览器上session的cookie值进行加密 24 SESSION_KEY_PREFIX = "session:" # sessionID的前缀,默认就是 session: 25 26 app.config.from_object(Config) 27 #SQLAlchemy加载配置项 28 db.init_app(app) 29 #Session加载配置项 30 session_store.init_app(app) 31 32 from flask import session 33 @app.route("/set") 34 def set_session(): 35 session["uname"] = "xiaoming" 36 session["age"] = 18 37 return "ok" 38 39 @app.route("/get") 40 def get_session(): 41 print(session.get("uname")) 42 print(session.get("age")) 43 return "ok" 44 45 @app.route("/del") 46 def del_session(): 47 48 print(session.pop("uname")) 49 print(session.pop("age")) 50 return "ok" 51 52 if __name__ == '__main__': 53 with app.app_context(): 54 db.create_all() 55 app.run()
这个功能必须确保,服务器必须已经安装了redis而且当前项目虚拟环境中已经安装了redis扩展库
pip install flask-redis -i https://pypi.douban.com/simple # flask-redis是第三方开发者为了方便我们在flask框架中集成redis数据库操作所封装一个redis操作库、 # 在flask中要基于flask-redis进行数据库则可以完成以下3个步骤即可: # 1. 引入flaskRedis并实例化 from flask_redis import FlaskRedis redis = FlaskRedis() redis.init_app(app) # 2. 在config配置中使用 REDIS_URL配置redis的url地址 REDIS_URL = "redis://:password@localhost:6379/0" # 3. 使用实例化后的flaskRedis对象即可操作redis数据库,这个库就是我们之前在django中操作redis时使用库 # 直接通过 redis对象.命令方法(参数1, 参数2...) redis.setex("sms",5 * 60 , "10010")
1 from flask import Flask 2 from flask_sqlalchemy import SQLAlchemy 3 from flask_session import Session 4 app = Flask(__name__) 5 db = SQLAlchemy() 6 session_store = Session(app) 7 8 from flask_redis import FlaskRedis 9 redis_session = FlaskRedis() 10 class Config(object): 11 DEBUG = True 12 SECRET_KEY = "*(%#4sxcz(^(#$#8423" # session秘钥 13 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" 14 SQLALCHEMY_TRACK_MODIFICATIONS = False 15 SQLALCHEMY_ECHO = False 16 # redis连接地址 redis://用户名:密码@IP地址:端口/数据库名 17 REDIS_URL = "redis://:@127.0.0.1:6379/15" 18 # 把session保存到redis 19 SESSION_TYPE = "redis" # session存储方式为redis 20 SESSION_PERMANENT = False # 如果设置session的生命周期是否是会话期, 为True,则关闭浏览器session就失效 21 SESSION_USE_SIGNER = False # 是否对发送到浏览器上session的cookie值进行加密 22 SESSION_KEY_PREFIX = "session:" # 保存到redis的session数的名称前缀 23 # session保存数据到redis时启用的链接对象 24 SESSION_REDIS = redis_session # 用于连接redis的配置 25 26 app.config.from_object(Config) 27 db.init_app(app) 28 session_store.init_app(app) 29 redis_session.init_app(app) 30 31 32 from flask import session 33 @app.route("/set") 34 def set_session(): 35 session["uname"] = "xiaoming" 36 session["age"] = 18 37 return "ok" 38 39 @app.route("/get") 40 def get_session(): 41 print(session.get("uname")) 42 print(session.get("age")) 43 return "ok" 44 45 @app.route("/del") 46 def del_session(): 47 48 print(session.pop("uname")) 49 print(session.pop("age")) 50 return "ok" 51 52 if __name__ == '__main__': 53 with app.app_context(): 54 db.create_all() 55 app.run()
四、flask项目配置另一种写法
from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_session import Session app = Flask(__name__) db = SQLAlchemy() session_store = Session(app) from flask_redis import FlaskRedis redis_session = FlaskRedis() class Config(object): DEBUG = True SECRET_KEY = "*(%#4sxcz(^(#$#8423" # session秘钥 SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ECHO = False # 另一种编写flask配置的方式 app.config.from_object(Config) app.config["REDIS_URL"] = "redis://:@127.0.0.1:6379/15" app.config["SESSION_TYPE"] = "redis" # session存储方式为redis app.config["SESSION_PERMANENT"] = False # 如果设置session的生命周期是否是会话期, 为True,则关闭浏览器session就失效 app.config["SESSION_USE_SIGNER"] = False # 是否对发送到浏览器上session的cookie值进行加密 app.config["SESSION_KEY_PREFIX"] = "session:" # 保存到redis的session数的名称前缀 app.config["SESSION_REDIS"] = redis_session # 用于连接redis的配置 db.init_app(app) session_store.init_app(app) redis_session.init_app(app) from flask import session @app.route("/set") def set_session(): session["uname"] = "xiaoming" session["age"] = 18 return "ok" @app.route("/get") def get_session(): print(session.get("uname")) print(session.get("age")) return "ok" @app.route("/del") def del_session(): print(session.pop("uname")) print(session.pop("age")) return "ok" if __name__ == '__main__': with app.app_context(): db.create_all() app.run()