带有 SQLAlchemy 的 Postgres 中的枚举数组

Tim*_*win 6 python arrays postgresql enums sqlalchemy

在过去的一年里,我一直在使用一系列带有 postgres 和 SQLAlchemy 的枚举,如下所示:

class MyModel(BaseModel):
    enum_field = Column(postgresql.ARRAY(EnumField(MyEnum, native_enum=False)))
Run Code Online (Sandbox Code Playgroud)

EnumField来自sqlalchemy_enum34库,这是一个围绕内置枚举的小包装器,它使用 Python 枚举作为 Python 表示而不是字符串。

尽管文档说不支持枚举数组,但我想它有效,因为我选择了“native_enum=False”。最近我发现它不再工作了,我认为这是由于从 SQLA 1.0 升级到 1.1,但我不确定。

问题是,它生成了无效的 DQL:

CREATE TABLE my_model (
    enum_field VARCHAR(5)[3] NOT NULL CHECK (contexts IN ('ONE', 'TWO', 'THREE'))
)
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

ERROR:  malformed array literal: "ONE"
DETAIL:  Array value must start with "{" or dimension information.
Run Code Online (Sandbox Code Playgroud)

知道如何取回枚举数组吗?
顺便说一句:当它工作时,实际上没有创建 CHECK 约束,只是一个变化的数组。只要我可以在我的 Python 代码中使用枚举,我就可以接受(例如query.filter(enum_field==MyEnum.ONE)

lov*_*per 5

我在 SqlAlchemy 源代码中找到了很好的解决方法:

import re

from sqlalchemy import TypeDecorator, cast
from sqlalchemy.dialects.postgresql import ARRAY


class ArrayOfEnum(TypeDecorator):

    impl = ARRAY

    def bind_expression(self, bindvalue):
        return cast(bindvalue, self)

    def result_processor(self, dialect, coltype):
        super_rp = super(ArrayOfEnum, self).result_processor(dialect, coltype)

        def handle_raw_string(value):
            inner = re.match(r"^{(.*)}$", value).group(1)

            return inner.split(",") if inner else []

        def process(value):
            if value is None:
                return None

            return super_rp(handle_raw_string(value))

        return process
Run Code Online (Sandbox Code Playgroud)

现在:

achievements = Column(ArrayOfEnum(Enum(AchievementsType)))
Run Code Online (Sandbox Code Playgroud)

进而:

career.achievements = [AchievementsType.world, AchievementsType.local]
Run Code Online (Sandbox Code Playgroud)


Tim*_*win 0

Mike Bayer在sqlalchemy 邮件列表上回答:

您可能想添加 create_constraint=False ,看看是否有效

http://docs.sqlalchemy.org/en/latest/core/type_basics.html?highlight=enum#sqlalchemy.types.Enum.params.create_constraint

我现在可以创建表(无需任何检查)。