SqlAlchemy 2.0:在 ORM 表定义中使用 `mapped_column()` 和 `Compulated()` 列时出现问题(不起作用)

问题描述 投票:0回答:1

(注:我将在下面回答我自己的问题。但是,评论, 欢迎其他见解或替代方法!我收到了 F. Caselli 在 SQLAlchemy 论坛上提供的宝贵帮助,其中 帮助我缩小了寻找解决方案的范围。)

您好,我正在尝试在 SqlAlchemy 2.0 中使用 mapped_column() 直接在 ORM 定义

中创建一个 
COMPUTED 列,但我没有成功(我检查了 Google 并尝试找到答案在文档中)。

我知道对于核心模型,通过以下方式声明一个表就足够了(玩具示例,其中

"area"
是一个计算列):

square = Table(
    "square",
    metadata_obj,
    Column("id", Integer, primary_key=True),
    Column("side", Integer),
    Column("area", Integer, Computed("side * side")),
)

这相当于以下 SQL DDL 语句 (Postgresql >12):

CREATE TABLE square (
    id SERIAL NOT NULL,
    side INTEGER,
    area INTEGER GENERATED ALWAYS AS (side * side) STORED,
    PRIMARY KEY (id)
)

但是,当尝试使用 Mapped[]

mapped_column()
ORM
中执行等效操作时,我似乎找不到解决方案。

我想象下面的东西可能会起作用,但事实并非如此:

class Square(Base):
    ...
    area: Mapped[int] = mapped_column(Computed("side*side"))

在此之前,我还尝试过其他配置,例如将

Computed()
传递为
server_default=
,以及使用
FetchedValue
,但在所有情况下,我都遇到了错误。

我也来到了

@hybrid_property
,但我知道它不一样(因为我需要计算列成为表的DDL定义的一部分,并且
@hybrid_property
似乎让计算在选择期间完成,而不是作为DDL ).

如果有人能指导我正确使用

mapped_column()
Computed()

,我将不胜感激
python sqlalchemy orm ddl
1个回答
0
投票

发现缺失的部分只是参数

area: Mapped[int] = mapped_column(Computed("side*side"))
后,我们能够缩小搜索范围,使
init=False

发挥作用

原来我的

Base
是从
MappedAsDataclass
派生而来的,而数据类的
__init__()
方法的创建并没有按照此类
Base
类的要求正确处理。

显然,

MappedAsDataclass
机制不会自动从
Computed()
方法中排除
__init__()
列,因此我们必须在
init=False
定义中显式设置
mapped_column()

总而言之,我的案例的解决方案是声明

area
列,如下所示:


class Base(MappedAsDataclass, DeclarativeBase):
    pass

class Square(Base):
    ...
    # if computed column use init=False if Base is a MappedAsDataclass
    area: Mapped[int] = mapped_column(Computed("side*side"), init=False) 
    ...

感谢 F. Caselli 帮助缩小了解决方案的搜索范围 sqlalchemy 论坛!!

© www.soinside.com 2019 - 2024. All rights reserved.