Flask数据库篇

定义模型

Flask-SQLAlchemy是Flask的一个数据库框架。

创建一个SQLAlchemy类的实例,表示应用使用的数据库,通过它可以获得Flask-SQLAlchemy提供的所有功能。

1
2
3
4
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object(config[config_name])
db = SQLAlchemy(app)

创建完SQLAlchemy的实例db,还需要定义模型。模型一般是一个Python类,类中的属性对应于数据库表中的列。

Flask-SQLAlchemy创建的数据库实例为模型提供了一个基类以及一系列辅助类和辅助函数,可用于定义模型结构。

Flask-SQLAlchemy要求每个模型都定义主键,通常命名为id

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from . import db

class Role(db.Model):# 继承基类
__tablename__ = 'roles' # 这是数据库中的表名
id = db.Column(db.Integer, primary_key=True) # primary_key是主键
name = db.Column(db.String(64), unique=True) # unique代表列中不可出现重复的值

def __repr__(self):
return '<Role %r>' % self.name

class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True) # 第一个参数代表了该属性的值的类型
# string,Integer,Float,Boolean等等
username = db.Column(db.String(64), unique=True, index=True)
age = db.Column(db.Integer)

def __repr__(self):
return '<User %r>' % self.username

关系型数据库使用关系把不同表中的行联系起来。如下,角色到用户是一对多关系,一个角色可以属于多个用户,但一个用户只能由一个角色。

1
2
3
4
5
6
7
8
9
10
class Role(db.Model):
...
# db.relationship的第一个参数表明这个关系的另一端是哪个模型,一role对多user
# backref向User模型中添加一个role属性,通过它可以获取对应的Role模型对象,不用再通过外键了
users = db.relationship('User', backref='role', lazy='dynamic')

class User(db.Model):
...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) # 外键,建立起两个表的关系
# role_id这列的值是roles表中相应行的id值

数据库的样子大概是:

1
2
3
4
5
表users
column id username age role_id role
row 1 1 zxy 20 1 Role1
2 2 cj 17 1 Role1
3 3 tianhong 21 2 Role2
1
2
3
4
表roles
column id name users
row 1 1 student [zxy, cj]
2 2 coder [tianhong]

对于一个Role类的实例,其users属性会返回所有与角色相关联的用户列表。


创建数据库

开始需要先创建一个数据库

1
2
$ flask shell # 在这之前需要将创建app的py文件设为环境变量FLASK_APP的值
db.create_all()

下面这段代码创建一些角色和用户

1
2
3
4
5
>>> from model import Role, User
>>> admin_role = Role(name='Admin')
>>> user_role = Role(name='jason')
>>> me = User(name='TianHongZXY', role=admin_role)
>>> jason = User(name='Jason', role=user_role)

对数据库的改动通过数据库会话管理,在Flask-SQLAlchemy中,会话由db.session表示。

1
2
3
4
5
6
>>> db.session.add(admin_role)
>>> db.session.add(user_role)
>>> db.session.add(me)
>>> db.session.add(jason)
或者简写为
>>> db.session.add_all([admin_role, user_role, me, jason])

为了把对象写入数据库,我们要调用commit()方法提交会话才行。

db.session.commit()

注意:数据库会话db.session和Flask session对象没有关系,数据库会话也称为事务

关于数据库的查询query以及其他方法见官方文档。


数据库迁移

在开发数据库时有时需要修改上面定义的数据库模型,而且修改后还需要更新数据库。

Flask应用可以使用Flask-Migrate扩展,这个扩展是对Alembic的轻量级包装,并与flask命令做了集成。

扩展的初始化方法如下

1
2
3
from flask_migrate import Migrate
# ...
migrate = Migrate(app, db)

(venv) $ flask db init 在新项目中添加数据库迁移支持,添加一次就行。

这个命令会创建migrations目录,所有迁移脚本都存放在这里。

  • 使用Flask-Migrate管理数据库模式变化的步骤如下:
    1. 对模型进行修改
    2. 执行 flask db migrate命令,自动创建一个迁移脚本
    3. 检查生成的脚本是否和自己对模型进行的修改一致
    4. 把迁移脚本纳入版本控制
    5. 执行flask db upgrade命令,把迁移应用到数据库中。

更新数据库

这一步就比较简单了,直接执行下面的命令

(venv) $ flask db upgrade

该命令就是把改动应用到数据库中,且不影响保存的数据。


添加几个迁移

在开发项目,往往需要多次修改数据库。如果前一个迁移还没提交,可以继续在哪个迁移中修改,以免创建大量无意义的小迁移脚本。在前一个迁移脚本的基础上修改的步骤如下:

  1. 执行flask db downgrade命令,还原前一个脚本对数据库的改动(注意,这可能导致部分数据丢失)。
  2. 删除前一个迁移脚本,因为它已经没用了。
  3. 改动模型,执行flask db migrade生成新迁移脚本。
  4. 根据前面的说明,检查并应用新脚本。

参考资料:Flask Web开发(第二版)