如何根据子对象中的关系在SQLAlchemy中创建条件关系?

时间:2016-05-06 18:45:55

标签: python sqlalchemy relationship

我正在尝试在对象上创建一个名为 children_with_grandchild 的条件关系,该对象仅包含至少有一个对象>孙即可。我有这样的模型:

from sqlalchemy import Column, ForeignKey, Integer, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship

engine = create_engine('sqlite:///:memory:', echo=True)
Base = declarative_base()
Session = sessionmaker(bind=engine)


def setup():
    Base.metadata.create_all(engine)


class Parent(Base):
    __tablename__ = 'parent'

    id = Column(Integer, primary_key=True)

    children = relationship('Child', lazy='joined')


class Child(Base):
    __tablename__ = 'child'

    id = Column(Integer, primary_key=True)
    parent_id = Column(ForeignKey('parent.id'))

    grandchildren = relationship('GrandChild', lazy='joined')


class GrandChild(Base):
    __tablename__ = 'grandchild'

    id = Column(Integer, primary_key=True)
    child_id = Column(ForeignKey('child.id'))

到目前为止,我尝试过的功能是将类添加到类:

children_with_grandchild = relationship('Child',
                                        primaryjoin='and_(Parent.id==Child.parent_id,'
                                                    'Child.grandchildern.any())',
                                        lazy='joined')

根据我在尝试此操作时收到的错误消息,似乎只允许在 primaryjoin 属性中的条件中使用列,而不是关系。所以我也尝试将以下内容添加到类:

children_with_grandchild = relationship('Child',
                                        primaryjoin='and_(Parent.id==Child.parent_id,'
                                                    'Child.id==Grandchild.child_id)',
                                        lazy='joined')

但是,当我查询记录时,我遇到的错误是:

  

sqlalchemy.exc.OperationalError:(sqlite3.OperationalError)没有这样的列:grandchild.child_id

此错误似乎是由于包含 lazy ='join'属性引起的,因为如果我删除它,它可以正常工作。问题是查询优化我真的需要在初始查询中加载 childern_with_grandchild 关系。

鉴于以下测试数据, children_with_grandchild 的关系应仅包含 c1 子项,其中子项的关系将同时包含 c1 c2 子对象。

>>> setup()
>>> session = Session()
>>> p = Parent(id=1)
>>> c1 = Child(id=1, parent_id=1)
>>> c2 = Child(id=2, parent_id=1)
>>> gc1 = GrandChild(id=1, child_id=1)
>>> session.add_all([p, c1, c2, gc1])
>>> session.commit()
>>> p = session.query(Parent).first()

非常感谢任何帮助。谢谢!

1 个答案:

答案 0 :(得分:0)

我会尝试这样的事情

parent表格上添加

@property
def has_grandchildren(self):
    return any(child.grandchildren for child in self.children)

然后您可以通过某种形式

获取所有parents_with_no_grandchildren的列表
parents = session.query(Parent).all()
parents_with_no_grandchildren = [parent for parent in parents if not parent.has_grandchildren]