5.6 定义模型
Flask-SQLAlchemy 创建的数据库实例为模型提供了一个基类以及一系列辅助类和辅助函数,可用于定义模型的结构。图 5-1 中的 roles 表和 users 表可定义为模型 Role 和 User。
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
def __repr__(self)
return '<Role %r>' % self.name
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(64), unique=True, index=True)
def __repr__(self):
return '<User %r>' % self.username
5.7 关系
class Role(db.Model):
#...
users = db.relationship('User', backref='role')
class User(db.model):
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
如图所示,关系使用 users 表中的外键连接了两行。添加到 User 模型中的 role_id 列
被定义为外键,就是这个外键建立起了关系。传给 db.ForeignKey() 的参数 ‘roles.id’ 表
明,这列的值是 roles 表中行的 id 值。
添加到 Role 模型中的 users 属性代表这个关系的面向对象视角。对于一个 Role 类的实例,
其 users 属性将返回与角色相关联的用户组成的列表。 db.relationship() 的第一个参数表
明这个关系的另一端是哪个模型。如果模型类尚未定义,可使用字符串形式指定。
5.11 使用Flask-Migrate实现数据库迁移
配置Flask-Migrate
from flask——migrate import Migrate, MigrateCommand
#...
migrate = Migrate(app, db)
manager.add_command('db', MigrateCommand)
为了导出数据库迁移命令,Flask-Migrate 提供了一个 MigrateCommand 类,可附加到 Flask-
Script 的 manager 对象上。在这个例子中, MigrateCommand 类使用 db 命令附加。
在维护数据库迁移之前,要使用 init 子命令创建迁移仓库:
(venv) $ python hello.py db init
Creating directory /home/flask/flasky/migrations...done
Creating directory /home/flask/flasky/migrations/versions...done
Generating /home/flask/flasky/migrations/alembic.ini...done
Generating /home/flask/flasky/migrations/env.py...done
Generating /home/flask/flasky/migrations/env.pyc...done
Generating /home/flask/flasky/migrations/README...done
Generating /home/flask/flasky/migrations/script.py.mako...done
Please edit configuration/connection/logging settings in
'/home/flask/flasky/migrations/alembic.ini' before proceeding.
这个命令会创建 migrations 文件夹,所有迁移脚本都存放其中。数据库迁移仓库中的文件要和程序的其他文件一起纳入版本控制。
5.11.2 创建迁移脚本
在 Alembic 中,数据库迁移用迁移脚本表示。脚本中有两个函数,分别是 upgrade() 和downgrade() 。 upgrade() 函数把迁移中的改动应用到数据库中, downgrade() 函数则将改动删除。Alembic 具有添加和删除改动的能力,因此数据库可重设到修改历史的任意一点。
我们可以使用 revision 命令手动创建 Alembic 迁移,也可使用 migrate 命令自动创建。手动创建的迁移只是一个骨架, upgrade() 和 downgrade() 函数都是空的,开发者要使用Alembic 提供的 Operations 对象指令实现具体操作。自动创建的迁移会根据模型定义和数
据库当前状态之间的差异生成 upgrade() 和 downgrade() 函数的内容。
自动创建的迁移不一定总是正确的,有可能会漏掉一些细节。自动生成迁移脚本后一定要进行检查。
migrate 子命令用来自动创建迁移脚本:
(venv) $ python hello.py db migrate -m "initial migration"
INFO [alembic.migration] Context impl SQLiteImpl.
INFO [alembic.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate] Detected added table 'roles'
INFO [alembic.autogenerate] Detected added table 'users'
INFO [alembic.autogenerate.compare] Detected added index
'ix_users_username' on '['username']'
Generating /home/flask/flasky/migrations/versions/1bc
594146bb5_initial_migration.py...done
检查并修正好迁移脚本之后,我们可以使用 db upgrade 命令把迁移应用到数据库中:
(venv) $ python hello.py db upgrade
INFO [alembic.migration] Context impl SQLiteImpl.
INFO [alembic.migration] Will assume non-transactional DDL.
INFO [alembic.migration] Running upgrade None -> 1bc594146bb5, initial migration
对第一个迁移来说,其作用和调用 db.create_all() 方法一样。但在后续的迁移中,upgrade 命令能把改动应用到数据库中,且不影响其中保存的数据。