本文介绍了在烧瓶中创建种子数据 - 迁移或alembic迁移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在我的第一次迁移中插入一些种子数据?如果迁移不是最好的地方,那么最好的做法是什么?

 空消息

修订编号:384cfaaaa0be
修正:无
创建日期:2013-10-11 16:36:34.696069


$ b由Alembic使用的$ b#修订标识符。
revision ='384cfaaaa0be'
down_revision = None

from alembic import op
import sqlalchemy as sa


def upgrade ():
###由Alembic自动生成的命令 - 请调整! ###
op.create_table('list_type',
sa.Column('id',sa.Integer(),nullable = False),
sa.Column('name', ('name')

。 create_table('job',
sa.Column('id',sa.Integer(),nullable = False),
sa.Column('list_type_id',sa.Integer(),nullable = False ),
sa.Column('record_count',sa.Integer(),nullable = False),
sa.Column('status',sa.Integer(),nullable = False),
sa.Column('sf_job_id',sa.Integer(),nullable = False),
sa.Column('created_at',sa.DateTime(),nullable = False),
sa。列('compressed_csv',sa.LargeBinary(),nullable = True),
sa.ForeignKeyConstraint(['list_type_id'],['list_type.id'],),
sa.PrimaryKeyConstraint(' id')

###结束语法命令###

#==> INSERT SEED DATA HERE< ==


def downgrade():
###由Alembic自动生成的命令 - 请调整! ###
op.drop_table('job')
op.drop_table('list_type')
### end Alembic命令###

解决方案

Alembic有一个操作,。该文档给出了下面的例子(包括我已经包含的一些修复):

  from datetime import date 
from sqlalchemy .sql导入表,列sqlalchemy中的
导入字符串,整型,日期$ b $ from alembic导入op

#创建用于insert语句的ad-hoc表。
accounts_table = table('account',
column('id',Integer),
column('name',String),
column('create_date',Date)


op.bulk_insert(accounts_table,
[
{'id':1,'name':'John Smith',
'create_date ':date(2010,10,5)},
{'id':2,'name':'Ed Williams',
'create_date':date(2007,5,27)},
{'id':3,'name':'Wendy Jones',
'create_date':date(2008,8,15)},
]

请注意,alembic有一个操作,它与普通的 SQLAlchemy中的execute()函数:您可以运行任何您希望的SQL,如文档示例所示:

 从sqlalchemy.sql导入表中,列
f rom sqlalchemy import字符串
从alembic导入op

account = table('account',
column('name',String)

op .execute(
account.update()。\
where(account.c.name == op.inline_literal('account 1'))。\
values({'name ':op.inline_literal('account 2')})

注意用于创建在 update 语句中使用的元数据的表直接在模式中定义。这可能看起来像是打破了(不是你的应用程序中已经定义的表),但实际上是相当的必要。如果您尝试使用作为应用程序一部分的表或模型定义,那么当您在应用程序中对表格/模型进行更改时,可能会中断此迁移。您的迁移脚本应该被设置为:更改模型的未来版本不应更改迁移脚本。使用应用程序模型意味着定义将根据您检出的模型的版本(最可能是最新版本)而变化。因此,您需要将表定义自包含在迁移脚本中。



另外要讲的是,是否应该将种子数据放入运行的脚本作为自己的命令(如使用Flask-Script命令,如其他答案所示)。这可以使用,但你应该小心。如果你正在加载的数据是测试数据,那么这是一回事。但是我已经将种子数据理解为应用程序正常工作所需的数据。例如,如果您需要在角色表中设置admin和user的记录。这个数据应该作为迁移的一部分被插入。请记住,脚本只能用于数据库的最新版本,而迁移将与您要迁移到的特定版本一起使用。如果您想要脚本加载角色信息,则可能需要为角色表使用不同架构的每个数据库版本的脚本。另外,依靠一个脚本,你将会使得在迁移之间运行脚本变得更加困难(例如,迁移3-> 4需要种子数据在最初的迁移是在数据库中)。您现在需要修改Alembic的默认运行方式来运行这些脚本。这还不能忽视这些脚本将不得不随时间而改变的问题,谁知道你的应用程序版本是从源代码控制中检出的。

How can I insert some seed data in my first migration? If the migration is not the best place for this, then what is the best practice?

"""empty message

Revision ID: 384cfaaaa0be
Revises: None
Create Date: 2013-10-11 16:36:34.696069

"""

# revision identifiers, used by Alembic.
revision = '384cfaaaa0be'
down_revision = None

from alembic import op
import sqlalchemy as sa


def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.create_table('list_type',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('name', sa.String(length=80), nullable=False),
    sa.PrimaryKeyConstraint('id'),
    sa.UniqueConstraint('name')
    )
    op.create_table('job',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('list_type_id', sa.Integer(), nullable=False),
    sa.Column('record_count', sa.Integer(), nullable=False),
    sa.Column('status', sa.Integer(), nullable=False),
    sa.Column('sf_job_id', sa.Integer(), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('compressed_csv', sa.LargeBinary(), nullable=True),
    sa.ForeignKeyConstraint(['list_type_id'], ['list_type.id'], ),
    sa.PrimaryKeyConstraint('id')
    )
    ### end Alembic commands ###

    # ==> INSERT SEED DATA HERE <==


def downgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('job')
    op.drop_table('list_type')
    ### end Alembic commands ###
解决方案

Alembic has, as one of its operation, bulk_insert(). The documentation gives the following example (with some fixes I've included):

from datetime import date
from sqlalchemy.sql import table, column
from sqlalchemy import String, Integer, Date
from alembic import op

# Create an ad-hoc table to use for the insert statement.
accounts_table = table('account',
    column('id', Integer),
    column('name', String),
    column('create_date', Date)
)

op.bulk_insert(accounts_table,
    [
        {'id':1, 'name':'John Smith',
                'create_date':date(2010, 10, 5)},
        {'id':2, 'name':'Ed Williams',
                'create_date':date(2007, 5, 27)},
        {'id':3, 'name':'Wendy Jones',
                'create_date':date(2008, 8, 15)},
    ]
)

Note too that the alembic has an execute() operation, which is just like the normal execute() function in SQLAlchemy: you can run any SQL you wish, as the documentation example shows:

from sqlalchemy.sql import table, column
from sqlalchemy import String
from alembic import op

account = table('account',
    column('name', String)
)
op.execute(
    account.update().\
        where(account.c.name==op.inline_literal('account 1')).\
        values({'name':op.inline_literal('account 2')})
        )

Notice that the table that is being used to create the metadata that is used in the update statement is defined directly in the schema. This might seem like it breaks DRY (isn't the table already defined in your application), but is actually quite necessary. If you were to try to use the table or model definition that is part of your application, you would break this migration when you make changes to your table/model in your application. Your migration scripts should be set in stone: a change to a future version of your models should not change migrations scripts. Using the application models will mean that the definitions will change depending on what version of the models you have checked out (most likely the latest). Therefore, you need the table definition to be self-contained in the migration script.

Another thing to talk about is whether you should put your seed data into a script that runs as its own command (such as using a Flask-Script command, as shown in the other answer). This can be used, but you should be careful about it. If the data you're loading is test data, then that's one thing. But I've understood "seed data" to mean data that is required for the application to work correctly. For example, if you need to set up records for "admin" and "user" in the "roles" table. This data SHOULD be inserted as part of the migrations. Remember that a script will only work with the latest version of your database, whereas a migration will work with the specific version that you are migrating to or from. If you wanted a script to load the roles info, you could need a script for every version of the database with a different schema for the "roles" table.

Also, by relying on a script, you would make it more difficult for you to run the script between migrations (say migration 3->4 requires that the seed data in the initial migration to be in the database). You now need to modify Alembic's default way of running to run these scripts. And that's still not ignoring the problems with the fact that these scripts would have to change over time, and who knows what version of your application you have checked out from source control.

这篇关于在烧瓶中创建种子数据 - 迁移或alembic迁移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 23:43