[英]Query filter over ForeignKey in SQLAlchemy
为了简化,我有两个表(ORM FastAPI)
class Object(Base):
__tablename__ = "object"
id = Column('id', Integer, Identity(start=1), primary_key=True)
name = Column(VARCHAR2(30), unique=True, index=True)
attributes = relationship("Attributes", backref="parent", cascade="all, delete", passive_deletes=True)
class Attributes(Base):
__tablename__ = "attributes"
id = Column('id', Integer, Identity(start=1), primary_key=True)
attribute = Column(VARCHAR2(200), index=True)
value = Column(VARCHAR2(2000), index=True)
parent_id = Column(Integer, ForeignKey("object.id",ondelete="CASCADE"), nullable=False)
一个 object 可以有多个属性(1-N 关系)。 属性是动态的(取决于 object,有些对象有 10 个属性,或者 50...)
例如:
Object | Attributes
---------------------------------
Object 1 | color = red
| form = round
| level = 5
| ...
| attribute alpha
---------------------------------
Object 2 | color = red
| form = square
| level = 2
| ...
| attribute beta
我想做类似的事情:
“查找所有对象,其中 attribute.color = red 和 attribute.level >= 2 和 attribute.X 被定义”
我试过了:
query = db.query(Object).options(
joinedload(Attributes,innerjoin=False)).join(Attributes)
query = query.filter(Attributes.attribute == 'color')
query = query.filter(Attributes.value == 'red')
...
return query.all()
但我不知道如何在表属性上级联过滤器..
谢谢你的帮助...
要实现过滤器,我会使用any()
:
query = (
session.query(Object)
# -- NOTE: below join is not needed for the filter part;
# .options(joinedload(Attributes, innerjoin=False))
# .join(Attributes)
# add additional criteria
.filter(
Object.attributes.any(
and_(
Attributes.attribute == "color",
Attributes.value == "red",
)
)
)
.filter(
Object.attributes.any(
and_(
Attributes.attribute == "level",
func.cast(Attributes.value, Integer) >= 2,
)
)
)
.filter(Object.attributes.any(Attributes.attribute == "X")) # exists
)
这将产生 SQL 语句(具体取决于数据库引擎):
SELECT object.id,
object.name
FROM object
WHERE (EXISTS
(SELECT 1
FROM attributes
WHERE object.id = attributes.parent_id
AND attributes.attribute = 'color'
AND attributes.value = 'red'))
AND (EXISTS
(SELECT 1
FROM attributes
WHERE object.id = attributes.parent_id
AND attributes.attribute = 'level'
AND CAST(attributes.value AS INTEGER) >= 2))
AND (EXISTS
(SELECT 1
FROM attributes
WHERE object.id = attributes.parent_id
AND attributes.attribute = 'X'))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.