postgresql 我可以用SQLAchemy MappedAsDataclass创建Postgres `GENERATED ALWAYS AS`列吗?

von4xj4u  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(1)|浏览(127)

在我的项目(一个由SQLAlchemy创建和管理的Postgres数据库)中,我使用MappedAsDataclass和DeclarativeBase来创建这样的表:

class Base(MappedAsDataclass, DeclarativeBase):
    """subclasses will be converted to dataclasses"""

class Collection(Base):
    __tablename__ = 'collections'
    collection_id: Mapped[int] = mapped_column(init=False, primary_key=True)
    collection_name: Mapped[str] = mapped_column(default=None, unique = True)

User.__table__

Collection.metadata.create_all(engine)

字符串
我想用计算列'ezname'创建这个表,它从'collection_name'中的条目中删除空格,并用'_'下划线替换它们。
我可以通过创建上面的表,然后运行原始的Postgres命令来获得我想要的:

ALTER TABLE collections ADD column ezname varchar GENERATED ALWAYS AS (REGEXP_REPLACE(collection_name, ' ', '_')) stored;


有没有办法在ORM模型中创建这个列,特别是在使用MappedAsDataclass和DeclarativeBase声明表时?
在我阅读文档的过程中,我遇到了@hybrid_propertycolumn_property,但是到目前为止,我试图让它们与我的Map数据类模式一起工作的尝试都失败了。
我一直在尝试这样的东西(这显然没有工作)

class Collection(Base):
    __tablename__ = 'collections'
    collection_id: Mapped[int] = mapped_column(init=False, primary_key=True)
    collection_name: Mapped[str] = mapped_column(default=None, unique = True)
    collection_ezname: Mapped[str] = mapped_column(default=None, unique = True, Computed(REGEXP_REPLACE(collection_name, ' ', '_')))


所以首先我想知道SQLA是否可以做到这一点,如果可以,如何做到?
请注意,对我来说重要的是,一旦创建,逻辑就成为表本身的一部分,因此可以在ORM上下文之外移植。

qyswt5oh

qyswt5oh1#

你差点就成功了,你可以用这个。

from sqlalchemy import Computed, create_engine, func, select
from sqlalchemy.orm import Mapped, MappedAsDataclass, DeclarativeBase, Session, mapped_column

class Base(MappedAsDataclass, DeclarativeBase):
    pass

class Collection(Base):
    __tablename__ = 'collections'
    collection_id: Mapped[int] = mapped_column(init=False, primary_key=True)
    collection_name: Mapped[str] = mapped_column(default=None, unique=True)
    collection_ezname: Mapped[str] = mapped_column(Computed(func.REGEXP_REPLACE(collection_name, ' ', '_')), unique=True, init=False)

engine = create_engine("")

Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)

with Session(engine) as session:
    session.add(Collection('something with space'))
    session.commit()

with Session(engine) as session:
    for i in session.scalars(select(Collection)):
        print(i)

字符串
这将生成以下内容

CREATE TABLE collections (
        collection_id SERIAL NOT NULL, 
        collection_name VARCHAR NOT NULL, 
        collection_ezname VARCHAR GENERATED ALWAYS AS (REGEXP_REPLACE(collection_name, ' ', '_')) STORED NOT NULL, 
        PRIMARY KEY (collection_id), 
        UNIQUE (collection_name), 
        UNIQUE (collection_ezname)
)


产出
第一个月

  • 您可能需要更改正则表达式,因为它目前无法替换多个空格和其他我无法想到的场景。可能是REGEXP_REPLACE(collection_name, ' ', '_', 'g')?*

相关问题