[英]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.