【问题标题】:how to set unique value for each row on alembic migration如何为alembic迁移的每一行设置唯一值
【发布时间】:2016-11-24 20:43:42
【问题描述】:

我为MyModel 模型添加了一个独特的属性uid

class MyModel(db.Model):
...
    uid = db.Column(db.String(50), nullable=False)
...
    __table_args__ = (UniqueConstraint('uid', name='unique_uid'),)

我有一个迁移:

def upgrade():
    op.add_column('mymodel', sa.Column('uid', sa.String(length=50), nullable=True))

    mymodel = table('mymodel', column('uid'))
    op.execute(mymodel.update().values(uid=generate_uid()))
    op.create_unique_constraint('unique_uid', 'mymodel', ['uid'])

    op.alter_column(
        table_name='mymodel',
        column_name='uid',
        nullable=False
    )

在运行 db upgrade 时出现错误:

...
psycopg2.IntegrityError: could not create unique index "unique_uid"
DETAIL:  Key (uid)=(c92U6txA2) is duplicated.

如何在 op.execute(mymodel.update().values(uid=generate_uid())) 上为每一行设置唯一值?

$ pip freeze
alembic==0.8.6
Flask==0.10.1
Flask-Fixtures==0.3.3
Flask-Login==0.3.2
Flask-Migrate==1.8.0
Flask-Script==2.0.5
Flask-SQLAlchemy==2.1
itsdangerous==0.24
Jinja2==2.8
Mako==1.0.4
MarkupSafe==0.23
psycopg2==2.6.1
python-editor==1.0
requests==2.10.0
SQLAlchemy==1.0.13
Werkzeug==0.11.9

【问题讨论】:

  • 什么是generate_uid()?你用的是什么数据库?
  • 我认为这并不重要。但尽管如此:generate_uid() 返回唯一值,如 1Er45gh78k;数据库是 PostgreSQL

标签: flask sqlalchemy alembic flask-migrate sqlalchemy-migrate


【解决方案1】:

可能的解决方案:

from sqlalchemy.orm import Session
from alembic import op
import sqlalchemy as sa

def upgrade():
    conn = op.get_bind()
    session = Session(bind=conn)

    op.add_column('mymodel', sa.Column('uid', sa.String(length=50), nullable=True))

    for item in session.query(MyModel).filter_by(uid=None):
        item.uid = generate_uid()
    session.commit()

    op.create_unique_constraint('unique_uid', 'mymodel', ['uid'])

    op.alter_column(
        table_name='mymodel',
        column_name='uid',
        nullable=False
    )

【讨论】:

  • 如果我对所有列进行更新,我会收到此错误 ERROR [root] 错误:所有 MySQL CHANGE/MODIFY COLUMN 操作都需要现有类型。
【解决方案2】:

您编写的迁移脚本将相同的 uid 放在所有行上,generate_uid() 函数被调用一次,然后将其结果添加到所有行中。因此,当创建索引时,您会收到重复键错误。

根据您的 uid 和数据库,您也许可以编写一条 SQL 语句来为所有行创建唯一 id,但安全的做法是执行循环并分别更新每一行。

【讨论】:

  • 我只想在迁移代码中获得解决方案(如果可能的话)。无需编写 SQL 代码。
  • @Meatbot 您可能没有意识到这一点,但是您在迁移脚本中的op.execute 行实际上正在运行SQL。如果您不想编写 SQL,则不必编写 SQL,如果您愿意,可以使用 SQLAlchemy,这不会改变答案。
  • 我已经有一个为 uid 列返回唯一值的函数 - generate_uid()。而且我不想将此功能克隆到数据库中。我想在我的迁移中应用这个功能。
  • 编写一个 Python 循环,每行调用一次此函数。
猜你喜欢
  • 2023-03-20
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
  • 2016-09-06
  • 2013-07-04
  • 2017-03-25
  • 2018-01-05
  • 1970-01-01
相关资源
最近更新 更多