如何在SQLAlchemy模型中使用SQLAlchemy Utils

6

我正在尝试创建一个使用 UUID 作为主键的用户模型:

from src.db import db # SQLAlchemy instance

import sqlalchemy_utils

import uuid


class User(db.Model):
    __tablename__ = 'user'

    id = db.Column(sqlalchemy_utils.UUIDType(binary=True), primary_key=True, nullable=False)

但是当我生成迁移时,我收到以下信息:
File "/home/pc/Downloads/project/auth/venv/lib/python3.6/site-packages/alembic/runtime/environment.py", line 836, in run_migrations
    self.get_context().run_migrations(**kw)
  File "/home/pc/Downloads/project/auth/venv/lib/python3.6/site-packages/alembic/runtime/migration.py", line 330, in run_migrations
step.migration_fn(**kw)
  File "/home/pc/Downloads/project/auth/migrations/versions/efae4166f832_.py", line 22, in upgrade
    sa.Column('id', sqlalchemy_utils.types.uuid.UUIDType(length=16), nullable=False),
NameError: name 'sqlalchemy_utils' is not defined`

我尝试明确地告知我正在使用的模块,就像这个一样,并使用了一个“内部”实现,SQLAlchemy

注意:如果我在/migrations/version/efae4166f832_.py中手动导入sqlalchemy_utils并删除自动生成的长度sa.Column('id', sqlalchemy_utils.types.uuid.UUIDType(length=16), nullable=False),它可以正常工作fine

我使用一个generate.py脚本生成迁移:

from src import create_app

from src.db import db

from flask_migrate import Migrate

# Models

from src.user.models.user import User

app = create_app()

migrate = Migrate(app, db)`

enter image description here

注意:MySQL引擎

我希望在生成迁移时,它可以生成一个使用SQLAlchemy Utils实现的UUID作为主键的用户模型。


如果您仍然遇到这个问题,您可以参考这里的答案。 - undefined
7个回答

13

您只需要添加:

import sqlalchemy_utils

将 script.py.mako 添加到 migrations 文件夹中的脚本中


1
我做了非常类似的事情 - 将该行添加到我的迁移/版本/9d34543545.py文件的顶部。 - Rimu Atkinson
如果我只是在script.py.mako文件中添加import语句,这并不足以解决问题。 - Iván
2
将import行添加到script.py.mako中,将自动将其添加到您生成的任何新迁移脚本中。如果您在一些先前的迁移脚本已经生成之后才添加了import行,则还必须手动将import行添加到先前生成的脚本中。 - djsosofresh

2
感谢,Marco,但我已经解决了。我已经将import sqlalchemy_utils导入到env.pyscript.py.mako中,我还加入了以下函数:

最初的回答

def render_item(type_, obj, autogen_context):
    """Apply custom rendering for selected items"""

    if type_ == "type" and isinstance(obj, sqlalchemy_utils.types.uuid.UUIDType):
        # Add import for this type
        autogen_context.imports.add("import sqlalchemy_utils")

        autogen_context.imports.add("import uuid")

        return "sqlalchemy_utils.types.uuid.UUIDType(), default=uuid.uuid4"

    # Default rendering for other objects
    return False

env.py文件中,我在run_migrations_online函数中设置了render_item=render_item

最初的回答

context.configure(
    ...,
    render_item=render_item,
    ...
)

我研究了如何自动完成此操作,但未能找到任何可以帮助我的东西。
操作的顺序很重要:
  1. export FLASK_APP=manage.py

  2. flask db init

  3. 按照上面的教程进行操作

  4. flask db migrate

  5. flask db upgrade

"Original Answer"翻译成"最初的回答"。

2

背景

如果您不必手动编辑每个迁移文件并添加 import sqlalchemy_utils 语句,那将是理想的。

查看 Alembic 文档script.py.mako 是“用于生成新迁移脚本的 Mako 模板文件。”因此,您需要重新生成迁移文件,并在迁移文件生成过程中使 Mako 自动导入 sqlalchemy_utils。

修复方法

如果可能,请删除旧的迁移文件(它们可能已经损坏),并像下面这样将 import sqlalchemy_utils 添加到您的 script.py.mako 文件中:

from alembic import op
import sqlalchemy as sa
import sqlalchemy_utils #<-- line you add
${imports if imports else ""}

然后只需重新运行您的alembic迁移:

alembic revision --autogenerate -m "创建初始表"

当您查看迁移文件时,您应该会看到sqlalchemy_utils已经通过mako脚本导入。

希望这有所帮助。


实际上,我不得不删除之前的迁移文件4564fde54544df.py,并将import sqlalchemy_utils添加到script.py.mako中才能运行。 - William Le

1
script.py.mako 文件中添加 import sqlalchemy_utils,将自动在生成的所有迁移文件中导入此行并解决问题。
from alembic import op
import sqlalchemy as sa
import sqlalchemy_utils
${imports if imports else ""}

0
import sqlalchemy_utils行添加到新创建的migrations/versions/{hash}_my_comment.py文件中。但是,这只会为迁移的特定步骤解决问题。如果您预计将对引用sqlalchemy_utils的列进行大量更改,则应该像Walter的建议那样采取更强大的措施。即使如此,看起来您可能需要添加代码来正确处理每个使用的列类型。
注意:尽管在多个地方看到了将导入行添加到script.py.mako文件中的建议,但这对我没有起作用。

0
在运行flask db upgrade之前,您需要检查您的迁移版本文件。 在这种情况下,我正在使用sqlalchemy_utils来处理我的应用程序模型。
所以只需导入sqlalchemy_utils即可解决此问题:
import sqlalchemy_utils

enter image description here


0
如果你想让alembic识别枚举类型,请按照以下步骤进行。
安装
pip install alembic-postgresql-enum or poetry add alembic-postgresql-enum

将import添加到envy.py中
import alembic_postgresql_enum

迁移将会自动生成。
def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.sync_enum_values('public', 'channel', ['USSD', 'WHATSAPP'],
                        [('subscription', 'channel')],
                        enum_values_to_rename=[])
    # ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.sync_enum_values('public', 'channel', ['WHATSAPP'],
                    [('subscription', 'channel')],
                    enum_values_to_rename=[])
# ### end Alembic commands ###

你可以在这里阅读更多关于这个套餐的信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接