愚蠢(但有效)的数据库模式和使用sqlalchemy的数据迁移框架。
sqlalchemygrate的Python项目详细描述
sqlalchemygrate sqlalchemygrate sqlalchemygrate
这是我愚蠢的(但有效的)迁移框架,构建在SQLAlchemy-世界上最好的数据库抽象库之上。grate不做像跟踪模式版本和单步升级/降级路径或测试这样的花哨事情。buuut,您可以使用upgrade命令在它周围创建一个包装器来执行所有这些操作。
有一件事grate在开箱即用时做得很好,那就是从一个sqlalchemy目标引擎到另一个引擎的逐行重复插入。这意味着您可以随意更改sqlalchemy模式,然后要导入数据,您可以创建另一个数据库,并逐行从旧数据集中重新插入到新数据集中。您甚至可以提供转换函数,以便在必要时转换数据。
警告:请考虑此测试质量。缺少错误检查,因此可能会引发恶意异常。正在添加更多功能和帮助程序。
使用量
Usage: grate COMMAND [ARGS ...] Really silly schema migration framework, built for SQLAlchemy. Commands: migrate ENGINE_FROM ENGINE_TO Migrate schema or data from one engine to another. upgrade ENGINE UPGRADE_FN Perform in-place upgrade of a schema in an engine. Examples: grate migrate "mysql://foo:bar@localhost/baz" "sqlite:///:memory:" \ --metadata model.meta:metadata --verbose grate upgrade "mysql://foo:bar@localhost/baz" migration.001_change_fancy_column:upgrade Hint: The upgrade command can also be used to downgrade, just point it to the relevant downgrade function. For extra awesomeness, use schema-altering DDLs provided by sqlalchemy-migrate. Options: -h, --help show this help message and exit -v, --verbose Enable verbose output. Use twice to enable debug output. --show-sql Echo SQLAlchemy queries. migrate: --only-tables=TABLES Only perform migration on the given tables. (comma- separated table names) --skip-tables=TABLES Skip migration on the given tables. (comma-separated table names) --limit=LIMIT Number to select per insert loop. (default: 100000) --metadata=METADATA MetaData object bound to the target schema definition. Example: model.metadata:MetaData --convert=FN (Optional) Convert function to run data through. Example: migration.v1:convert
函数示例
转换
迁移时,您可以提供转换函数以将数据导入。下面是一个人的样子:
# migration/v1.py: def convert(table, row): """ :param table: SQLAlchemy table schema object. :param row: Current row from the given table (immutable, must make a copy to change). Returns a dict with column:value mappings. """ if table.name == 'user': row = dict(row) row['email'] = row['email'].lower() elif table.name == 'job': row = dict(row) del row['useless_column'] return row
然后我们将这个函数与--convert=migration.v1:convert一起使用。使用这个特性会对性能造成相当明显的损害,即必须通过一个具有自己逻辑的函数来运行每一行,但是对于小数据集来说,这并不太糟糕,也不太方便忽略。
升级
执行升级命令时,可以在不完全重新插入的情况下进行就地更改。对于较大的数据集或较小的模式更改,这是一个更现实的替代方案。
# migration/001_add_fancy_column.py: from sqlalchemy import * from migrate import * # sqlalchemy-migrate lets us do dialect-agnostic schema changes # sqlalchemygrate also provides some helpers just in case from grate.migrations import table_migrate def upgrade(metadata): """ :param metadata: SQLAlchemy MetaData bound to an engine and autoreflected. """ fancy_table = metadata.tables['fancy_table'] # Create column using sqlalchemy-migrate col = Column('fancy_column', types.Integer) col.create(fancy_table) ## Or run some arbitrary SQL # metadata.bind.execute(...) ## Need to do a row-by-row re-insert? Use the table_migrate helper ## We do a migration from one engine to the same engine, but between two different tables this time. # table_migrate(metadata.bind, metadata.bind, table, renamed_table, convert_fn=None, limit=100000) def downgrade(metadata): fancy_table = metadata.tables['fancy_table'] fancy_table.c.fancy_column.drop()
如果将此功能与sqlalchemy-migrate结合使用,它将变得更强大。这样,你就可以使用方言不可知论者SQLAlchemy DDLs来生成模式改变,但不必依赖于SqLalchemy迁移的修订跟踪和其他不必要的复杂性,这促使我写下这一点。
现在我们可以升级和降级我们的模式,例如:
grate upgrade "sqlite:///development.db" migration.001_change_fancy_column:upgrade --show-sql grate upgrade "sqlite:///development.db" migration.001_change_fancy_column:downgrade --shoq-sql
也许这应该叫做upgrade以外的东西?也许是grade?无论如何…
性能说明
逐行重新插入(迁移)
数千行需要几秒钟,数百万行需要几分钟。详细信息取决于架构、服务器和特定数字。
就地架构更改(升级)
如果您没有执行完全的重新插入,那么这与使用任何其他模式迁移工具获得的效率差不多。通常以秒为单位。
有问题吗?想做贡献吗?
- 你可以在andrey.petrov@shazow.net
- 在@shazow发推特给我
- Open an issue或制作叉子:d
待办事项
- 更具体的例子(填写代码todos)
- 更多常用迁移操作的帮助程序
- 在grate周围构建一个包装器来处理修订跟踪,并逐步完成升级过程,就像大多数主流迁移框架一样。