Alembic的server_default和Postgres

时间:2018-09-27 06:25:11

标签: python postgresql sqlalchemy alembic

我想使用alembic从sqlalchemy模型迁移到另一个模型。 初始模型如下:

from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy_utils import UUIDType

class Foo(db.Model):
    __tablename__ = 'foo'
    id = db.Column(UUIDType(binary=True), primary_key=True)
    foo_field = db.Column(JSONB)

并且我想使foo_field不可为空:

class Foo(db.Model):
    __tablename__ = 'foo'
    id = db.Column(UUIDType(binary=True), primary_key=True)
    foo_field = db.Column(JSONB, nullable=False)

我想运行一个Alembic脚本来更改列,但是由于我现有的某些foo_field为空,因此我想在更改时使用server_default来应用默认值(一个空字典)

op.alter_column('foo',
         'foo_field',
         existing_type=postgresql.JSONB(astext_type=sa.Text()),
         nullable=False,
         server_default="{}")

我尝试了其他选项传递给此server_default,例如text("{}")lambda: {}{}text("SELECT '{}'")。但这似乎被忽略了,运行升级时,我得到的只是一个IntegrityError

sqlalchemy.exc.IntegrityError: (psycopg2.IntegrityError) column "foo_field" contains null values [SQL: 'ALTER TABLE foo ALTER COLUMN foo_field SET NOT NULL'] (Background on this error at: http://sqlalche.me/e/gkpj)

表示空字典的字符串是否被视为非空?该server_default应该传递什么?在将字段设置为不可为空之前,我是否应该分多步对代码进行填充以填充默认值(不是首选选项,我有一堆要对其应用的列)?

我使用的是postgres 10.5,我read认为postgres 11可以更好地处理这种操作,我现在应该切换到它吗?

提前感谢您的帮助/建议

1 个答案:

答案 0 :(得分:1)

您可以使用Rewriter,然后自己动手操作。

覆盖ops.AlterColumnOp操作并返回两个操作,第一个是具有服务器默认值的更新列操作,第二个是原始的op