有什么方法可以在Alembic中生成顺序的修订版ID?

时间:2018-11-14 15:37:57

标签: sqlalchemy database-migration alembic

我将Alembic用作Python项目的数据库迁移工具。当我运行这样的命令时:

alembic revision -m "adding a column"

...它将添加一个名为alembic/versions/xxxxxxxxxxxx_adding_a_column.py的新文件,其中xxxxxxxxxxxx是随机生成的12位数字的哈希。

从使人可读的角度来看,这有点问题,因为这意味着当查看alembic/versions目录时,所有文件将以随机顺序出现,而不是按顺序/按时间顺序显示订单。

Alembic中是否有任何选项可确保这些前缀修订版ID是连续的?我想我可以手动重命名文件,然后更新引用,但是我想知道是否已经有了类似的功能。

3 个答案:

答案 0 :(得分:5)

听起来,您对顺序列出的修订文件更感兴趣,而不是顺序订购的修订ID。前者无需更改版本ID的生成方式即可实现。

运行alembic init alembic时生成的alembic.ini文件具有配置修订文件命名的部分:

# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

这是文档中的解释:

  

file_template-这是用于生成新文件的命名方案   迁移文件。当前值是默认值,因此已注释   出来。可用的令牌包括:

     
      
  • %%(rev)s-版本ID
  •   
  • %%(slug)s-从修订消息派生的截断的字符串
  •   
  • %%(年)d,%%(月).2d,%%(天).2d,%%(小时).2d,%%(分钟).2d,%%(秒).2d-创建日期的组成部分,默认情况下为datetime.datetime.now(),除非还使用了时区配置选项。
  •   

因此,将file_template = %%(year)d-%%(month).2d-%%(day).2d_%%(rev)s_%%(slug)s添加到alembic.ini会将您的修订命名为2018-11-15_xxxxxxxxxxxx_adding_a_column.py

我发现了这个问题:https://bitbucket.org/zzzeek/alembic/issues/371/add-unixtime-stamp-to-start-of-versions向我指出了正确的方向。

A comment from from that issue

  

时间戳不一定告诉您哪个文件是最新的,   因为允许分支。 “历史史”本来就是最好的   真理的来源。

因此,文件命名解决方案不能保证在目录中按逻辑顺序进行迁移(但会对IMO有所帮助)。可以针对具有顺序编号的情况提出相同的论点。

如果您确实想指定自己的修订标识符,请在命令行上使用--rev-id标志。

例如:

alembic revision -m 'a message' --rev-id=1

生成了一个名为1_a_message.py的文件:

"""a message

Revision ID: 1
Revises:
Create Date: 2018-11-15 13:40:31.228888

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '1'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    pass


def downgrade():
    pass

因此,您绝对可以自己管理修订标识符。编写bash脚本以触发修订版本生成,并自动传递基于日期时间的rev_id,例如--rev-id=<current datetime>来控制目录中列出的顺序。

如果未指定修订版ID,则调用位于alembic.util.langhelpers的函数rev_id()

def rev_id():
    return uuid.uuid4().hex[-12:]

rev_id()的函数调用在该原始源中进行了硬编码,因此,如果没有猴子修补函数,将很难覆盖该行为。您可以创建一个库的派生分支,然后重新定义该函数,或者将其用于生成ID的函数配置为可配置的。

答案 1 :(得分:3)

在我的案例中,我找到了如何在没有额外 bash 脚本的情况下做到这一点,只是在 env.py 中使用了一些突变魔法。也许它会帮助某人。

Alembic 具有强大的 customizing generated revisions 功能,因此我们可以在此级别编写覆盖:

# env.py
def process_revision_directives(context, revision, directives):
    # extract Migration
    migration_script = directives[0]
    # extract current head revision
    head_revision = ScriptDirectory.from_config(context.config).get_current_head()
    
    if head_revision is None:
        # edge case with first migration
        new_rev_id = 1
    else:
        # default branch with incrementation
        last_rev_id = int(head_revision.lstrip('0'))
        new_rev_id = last_rev_id + 1
    # fill zeros up to 4 digits: 1 -> 0001
    migration_script.rev_id = '{0:04}'.format(new_rev_id)

...
# then use it context.configure
context.configure(
  ...
  process_revision_directives=process_revision_directives,
)

如果您还想将它用于没有 --autogenerate 创建的修订,您应该在 revision_environment 中将 alembic.ini 设置为 true

答案 2 :(得分:1)

我制作了一个脚本,用于根据####_模式中已经存在的迁移数量自动增加修订号。这是TLDR版本。我将其保存为migrations.sh并更改第2行中的路径

#!/usr/bin/env bash
NEXT_ID=`ls kennel/db/versions/* | grep -P '/\d{4}_.*\.py$' | wc -l`
alembic revision -m $@ --rev-id=`printf "%04d" ${NEXT_ID}`

然后您可以像使用它一样

./migrations.sh migration_name
# or 
./migrations.sh migration_name --autogenerate

完整的脚本包含文档,其默认值为--autogenerate,可以使用--empty标志将其禁用。 https://gist.github.com/chriscauley/cf0b038d055076a2a30de43526d4150e