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

二、模块推荐faker

文档: 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()
View Code

三、flask-session

session如如果不设置默认存储到系统的文件中,通过此模块允许设置session到指定存储的空间中, 文档:

安装命令: https://pythonhosted.org/Flask-Session/

pip install flask-session

使用session之前,必须配置一下配置项:

SECRET_KEY = "*(%#4sxcz(^(#$#8423" # session秘钥

3.1 SQLAlchemy存储session的基本配置

 需要手动创建session表,在项目第一次启动的时候,使用db.create_all()来完成创建。

只要配置项:

# 把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()
View Code

3.2 redis保存session的基本配置

 这个功能必须确保,服务器必须已经安装了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()
View Code

四、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()
原文地址:https://www.cnblogs.com/yj0405/p/14826693.html