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

soa*_*gem 2 sqlalchemy database-migration alembic

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

alembic revision -m "adding a column"
Run Code Online (Sandbox Code Playgroud)

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

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

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

小智 17

我发现如何在我的情况下做到这一点,无需额外的 bash 脚本,只需 env.py 中的一些突变魔法。也许它会对某人有所帮助。

Alembic 具有强大的功能,可以自定义生成的修订版本,因此我们可以在此级别编写覆盖:

# 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,
)
Run Code Online (Sandbox Code Playgroud)

如果您还想将其用于创建的修订版,--autogenerate则应revision_environment在中将其设置为 truealembic.ini

  • 另外,如果您有多个“context.configure”,您应该添加到所有这些 (2认同)

Sup*_*oot 12

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

alembic.ini运行时生成的文件alembic init alembic包含一个部分,用于配置修订文件的命名:

# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
Run Code Online (Sandbox Code Playgroud)

这是来自文档的解释:

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)salembic.ini会将您的修订命名为2018-11-15_xxxxxxxxxxxx_adding_a_column.py

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

来自该期的评论

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

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

如果确实要指定自己的修订标识符,请--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
Run Code Online (Sandbox Code Playgroud)

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

如果未指定版本ID,则在以下位置rev_id()找到的函数将alembic.util.langhelpers被调用:

def rev_id():
    return uuid.uuid4().hex[-12:]
Run Code Online (Sandbox Code Playgroud)

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

  • 这是很棒的信息。谢谢。这帮助我更容易地解决我们经常遇到的问题。如果有人在检查另一个功能分支之前忘记降级,“alembic History -i”将在无法找到头部时爆炸。加上日期前缀可以更轻松地找到罪魁祸首。为 revid 加上时间戳的内置方法仍然是梦想,因为这就是 alembic_version 中实际存在的内容。我们开始使用 `--rev-id $(date -u +"%Y%m%dT%H%M%SZ")` 和 `alembic revision`。 (4认同)
  • 遗憾的是没有内置选项来实现从 1 开始的简单自动递增整数。 (2认同)

chr*_*ley 5

我制作了一个脚本,根据已存在的匹配该####_模式的迁移数量来自动增加修订号。这是一个 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}`
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

./migrations.sh migration_name
# or 
./migrations.sh migration_name --autogenerate
Run Code Online (Sandbox Code Playgroud)

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