簡體   English   中英

如何將多表 case 語句添加到 @hybrid_property 表達式?

[英]How do I add a multi-table case statement to a @hybrid_property expression?

我正在嘗試在“父”表中創建一個@hybrid_property ,其中包含一個 case 語句,該語句從“子”表中輸出datetime時間值(如果存在)。 如果不是,那么它應該是原始表中的datetime時間值 output。 由於這兩個表之間的關系是一對一的,因此我將按照此處的指南進行操作。

我把這個 MRE 放在一起:

from sqlalchemy import Integer, Column, DateTime, case, create_engine, ForeignKey
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property
import datetime as dt

Base = declarative_base()

class TblParent(Base):

    __tablename__ = "tbl_parent"
    __table_args__ = {"schema": "test"}

    id_ = Column(Integer, primary_key=True)
    date_time = Column(DateTime)

    tbl_child_rel = relationship("TblChild", back_populates="tbl_parent_rel", uselist=False)

    @hybrid_property
    def date_time_hybrid(self):
        return

    @date_time_hybrid.expression
    def date_time_hybrid(cls):
        return case(
            [
                (cls.tbl_child_rel.date_time.__ne__(None), cls.tbl_child_rel.date_time),
            ],
            else_=cls.date_time,
        )


class TblChild(Base):

    __tablename__ = "tbl_child"
    __table_args__ = {"schema": "test"}

    id_ = Column(Integer, primary_key=True)
    date_time = Column(DateTime)
    tbl_parent_id = Column(Integer, ForeignKey("test.tbl_parent.id_"), unique=True)

    tbl_parent_rel = relationship("TblParent", back_populates="tbl_child_rel")


engine = create_engine(cn.CONN_STRING)
Session = sessionmaker(bind=engine)
session = Session()
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
session.add(TblParent(id_=1, date_time=dt.datetime(2000, 1, 1)))
session.add(TblChild(id_=1, date_time=dt.datetime(2000, 1, 1), tbl_parent_id=1))
session.commit()
qry = session.query(TblParent.date_time_hybrid)

當我運行它時出現錯誤:

AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with TblParent.tbl_child has an attribute 'date_time'

不確定我哪里出錯了? 提前致謝!

我正在使用 python 3.9.6 和 sqlalchemy 1.4.23。

下面應該工作:

@hybrid_property
def date_time_hybrid(self):
    return self.tbl_child_rel and self.tbl_child_rel.date_time or self.date_time

@date_time_hybrid.expression
def date_time_hybrid(cls):
    subq = (
        select([TblChild.date_time.label("date_time")])
        .where(TblChild.tbl_parent_id == cls.id_)
        .scalar_subquery()
    )
    return func.ifnull(subq, cls.date_time).label("date_time_hybrid")

下面是完全包含的工作示例:

import datetime as dt

from sqlalchemy import (
    Column,
    DateTime,
    ForeignKey,
    Integer,
    create_engine,
    func,
    select,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship, sessionmaker

Base = declarative_base()


class TblParent(Base):

    __tablename__ = "tbl_parent"
    # __table_args__ = {"schema": "test"}

    id_ = Column(Integer, primary_key=True)
    date_time = Column(DateTime)

    tbl_child_rel = relationship(
        "TblChild", back_populates="tbl_parent_rel", uselist=False
    )

    @hybrid_property
    def date_time_hybrid(self):
        return self.tbl_child_rel and self.tbl_child_rel.date_time or self.date_time

    @date_time_hybrid.expression
    def date_time_hybrid(cls):
        subq = (
            select([TblChild.date_time.label("date_time")])
            .where(TblChild.tbl_parent_id == cls.id_)
            .scalar_subquery()
        )
        return func.ifnull(subq, cls.date_time).label("date_time_hybrid")


class TblChild(Base):

    __tablename__ = "tbl_child"
    # __table_args__ = {"schema": "test"}

    id_ = Column(Integer, primary_key=True)
    date_time = Column(DateTime)
    tbl_parent_id = Column(Integer, ForeignKey("tbl_parent.id_"), unique=True)

    tbl_parent_rel = relationship("TblParent", back_populates="tbl_child_rel")


CONN_STRING = "sqlite:///:memory:"
engine = create_engine(CONN_STRING, echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)

parents = (p_no_child_no_dt, p_no_child_dt, p_child_no_dt, p_child_dt,) = (
    TblParent(id_=1, date_time=None),
    TblParent(id_=2, date_time=dt.datetime(2000, 1, 1)),
    TblParent(id_=3, date_time=dt.datetime(2000, 1, 2), tbl_child_rel=TblChild()),
    TblParent(
        id_=4,
        date_time=dt.datetime(2000, 1, 3),
        tbl_child_rel=TblChild(date_time=dt.datetime(2000, 1, 4)),
    ),
)
session.add_all(parents)
session.commit()
# qry = session.query(TblParent.date_time_hybrid)

# in-memory
session.expunge_all()
qry = session.query(TblParent)
for p in qry.all():
    print(p.id_, p.date_time_hybrid)

print("-" * 80)

# query
session.expunge_all()
qry = session.query(TblParent.id_, TblParent.date_time_hybrid)
for p in qry:
    print(p)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM