[英]How do I add a multi-table case statement to a @hybrid_property expression?
I'm trying to create a @hybrid_property
in a 'parent' table with a case statement that outputs a datetime
value from a 'child' table if one exists.我正在尝试在“父”表中创建一个
@hybrid_property
,其中包含一个 case 语句,该语句从“子”表中输出datetime
时间值(如果存在)。 If it doesn't then it should output the datetime
value from the original table.如果不是,那么它应该是原始表中的
datetime
时间值 output。 As the relationship between the two tables will be one-to-one then I'm following the guide here .由于这两个表之间的关系是一对一的,因此我将按照此处的指南进行操作。
I've put together this MRE:我把这个 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)
When I run it I get the error:当我运行它时出现错误:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with TblParent.tbl_child has an attribute 'date_time'
Not sure where I'm going wrong?不确定我哪里出错了? Thanks in advance!
提前致谢!
I'm using python 3.9.6 and sqlalchemy 1.4.23.我正在使用 python 3.9.6 和 sqlalchemy 1.4.23。
Below should work:下面应该工作:
@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")
Fully contained working example below:下面是完全包含的工作示例:
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.