SqlAlchemy - 按外键字段过滤

20 投票
1 回答
22372 浏览
提问于 2025-04-16 11:45

我想根据一个外键字段来筛选一个类的实例,但每次尝试时,我总是得到数据库中的所有条目,而不是符合条件的那些。

假设我有几个类,它们使用声明性基础,并且有一个简单的N:1关系。我是这样建模的:

#!/usr/bin/python2.6
class ContainerClass(declarativeBase):
     __tablename__ = "container_classes"
     _id = Column("id", Integer, primary_key=True)
     id = sqlalchemy.orm.synonym('_id', descriptor=property(getId, setId))


class WhateverClass(declarativeBase):
     __tablename__ = "whatever_classes"

     _id = Column("id", Integer, primary_key=True)
     _total = Column("total", Integer)
     _containerClassId = Column("container_class_id", Integer, ForeignKey("other_classes.id"))

     _containerClass = relationship("ContainerClass", uselist=False)

     id = sqlalchemy.orm.synonym('_id', descriptor=property(getId, setId))
     total = sqlalchemy.orm.synonym('_total', descriptor=property(getTotal, setTotal))
     containerClassId = sqlalchemy.orm.synonym('_containerClassId', decriptor=property(getContainerClassId, setContainerClassId))
     containerClass = sqlalchemy.orm.synonym('_containerClass', descriptor=property(getContainerClass setContainerClass))

一个“WhateverClass”的实例可以属于一个“ContainerClass”的实例(而每个ContainerClass可以有多个WhateverClass的实例)。这个关系看起来是正常的。如果我把一个新的“WhateverClass”添加到一个“ContainerClass”,那么这个whateverClass.containerClassId会正确地得到它所属的ContainerClass的值。

但是假设我需要获取属于id为5的“ContainerClass”的“WhateverClass”实例的列表。

如果我尝试这样做:

from myClasses import WhateverClass
session.query(WhateverClass.WhateverClass).filter(WhateverClass.WhateverClass.containerClass.id == 5).all()

我得到的是数据库中所有的WhateverClass实例,而不仅仅是那些与id为5的ContainerClass相关联的实例。

但是如果我这样做 session.query(WhateverClass.WhateverClass).filter(total <= 100).all(),我能正确地得到“total”字段小于等于100的WhateverClass实例。

我对sqlalchemy还很陌生……我需要使用连接查询之类的东西吗?我知道这应该不复杂,但我一直找不到合适的解决方案。我尝试过连接、并集……但(显然)我做错了什么。

我使用的是SqlAlchemy 0.6.6和Python 2.6(以防这有关系)

谢谢大家!

1 个回答

34

对于简单的查询,你可以直接进行查询:

session.query(WhateverClass).filter(WhateverClass._containerClassId == 5).all()

如果关系比较复杂,就需要使用连接查询:

session.query(WhateverClass).join(ContainerClass).filter(ContainerClass.id == 5).all()

撰写回答