![](/img/trans.png)
[英]SQLAlchemy raises error when inserting Postgres array of enum column
[英]Array of Enum in Postgres with SQLAlchemy
在过去的一年里,我一直在使用一系列带有 postgres 和 SQLAlchemy 的枚举,如下所示:
class MyModel(BaseModel):
enum_field = Column(postgresql.ARRAY(EnumField(MyEnum, native_enum=False)))
该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'))
)
我得到的错误是:
ERROR: malformed array literal: "ONE"
DETAIL: Array value must start with "{" or dimension information.
知道如何取回枚举数组吗?
顺便说一句:当它工作时,实际上没有创建 CHECK 约束,只是一个变化的数组。 只要我可以在我的 Python 代码中使用枚举,我就可以接受(例如query.filter(enum_field==MyEnum.ONE)
)
我在 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
现在:
achievements = Column(ArrayOfEnum(Enum(AchievementsType)))
进而:
career.achievements = [AchievementsType.world, AchievementsType.local]
当我需要一系列枚举时,我使用了 Mike Bayer 的食谱: https : //bitbucket.org/zzzeek/sqlalchemy/issues/3467/array-of-enums-does-not-allow-assigning#comment-19370832
编辑:问题移至https://github.com/sqlalchemy/sqlalchemy/issues/3467
也就是说,创建一个像这样的自定义类型:
import sqlalchemy as sa
class ArrayOfEnum(ARRAY):
def bind_expression(self, bindvalue):
return sa.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(",")
def process(value):
return super_rp(handle_raw_string(value))
return process
我已经有一段时间没有使用它了,所以我不确定它是否会继续工作。
它与您的 enum34 库的代码不同,所以也许它不会有同样的问题?
在现代 SqlAlchemy 中,您不必为此定义自定义类型:
import sqlalchemy.dialects.postgresql as pg
class MyModel(Base):
...
flags = Column(pg.ARRAY(sa.Enum(MyEnum,
create_constraint=False, native_enum=False)))
如果您在这里找到了自己的方式,将 SQLAlchemy 更新为 >=1.3.17 应该可以解决您的问题。
请参阅发行说明: https : //docs.sqlalchemy.org/en/13/changelog/changelog_13.html#change-e57f5913ab592a9c044cad747636edd8
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.