简体   繁体   English

Sqlalchemy 为父母过滤父子表

[英]Sqlalchemy filter parent and child table for parents

I have some models that I am trying to search, so I am looking to show return a result of all Parent objects, where either the Parent name is "foo" or the Child name is "foo".我有一些我正在尝试搜索的模型,因此我希望显示返回所有父对象的结果,其中父名称为“foo”或子名称为“foo”。

I have the query:我有一个查询:

parents = Session.query(Parent).\
            join(Child_s3).\
            filter(Parent.name.ilike("%foo%")).\
            filter(Child_s3.name.ilike("%foo%")).\
            order_by(asc(Product.name))

And the models:和模型:

class Parent(BaseSO):
    __tablename__ = 'parents'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(100), nullable=False, unique=True)
    colours = relationship('Child_s3', secondary=Parent_images, backref='Parentc')

class Child_s3(BaseSO):
    __tablename__ = 'children'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode)

Parent_images = Table(
    'Parent_images', BaseSO.metadata,
    Column('parent_id', Integer, ForeignKey('parents.id')),
    Column('child_id', Integer, ForeignKey('children.id'))
)

The query I have shows parents with the name of "foo" but does not show any parent objects, that also have children called "foo", can anyone help build this query to search both tables for the corresponding parent objects?我的查询显示了名为“foo”的父对象,但没有显示任何父对象,也有名为“foo”的子对象,任何人都可以帮助构建此查询以在两个表中搜索相应的父对象吗?

This code shows how to get the result using either an explicit join or a subquery:此代码显示如何使用显式连接或子查询来获取结果:

import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


Parent_images = sa.Table(
    'Parent_images', Base.metadata,
    sa.Column('parent_id', sa.Integer, sa.ForeignKey('parents.id')),
    sa.Column('child_id', sa.Integer, sa.ForeignKey('children.id'))
)


class Parent(Base):
    __tablename__ = 'parents'
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.Unicode(100), nullable=False, unique=True)
    colours = orm.relationship('Child_s3', secondary=Parent_images, backref='parents')

    def __repr__(self):
        return 'Parent(name=%s)' % self.name

    __str__ = __repr__


class Child_s3(Base):
    __tablename__ = 'children'
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.Unicode)

    def __repr__(self):
        return 'Child_s3(name=%s)' % self.name

    __str__ = __repr__


if __name__ == '__main__':
    engine = sa.create_engine('sqlite:///')
    Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine)
    Session = orm.sessionmaker(bind=engine)

    session = Session()
    for parent, child in [('boofoo', 'spam'), ('baz', 'foobar'), ('bar', 'quux')]:
        p1 = Parent(name=parent)
        session.add(p1)
        p1.colours.append(Child_s3(name=child))
    session.commit()

    print('Join')
    session = Session()
    q = (session.query(Parent)
                .join(Child_s3, Parent.colours)
                .filter(sa.or_(Parent.name.ilike('%foo%'),
                               Child_s3.name.ilike('%foo%'))))
    for p in q.all():
        print(p, p.colours)
    session.commit()
    print()

    print('Subquery')
    session = Session()
    q = (session.query(Parent)
                .filter(sa.or_(Parent.name.ilike('%foo%'),
                               Parent.colours.any(Child_s3.name.ilike('%foo%')))))
    for p in q.all():
        print(p, p.colours)
    session.commit()
    print()

The join query连接查询

q = (session.query(Parent)
            .join(Child_s3, Parent.colours)
            .filter(sa.or_(Parent.name.ilike('%foo%'),
                           Child_s3.name.ilike('%foo%'))))

generates this SQL生成这个 SQL

SELECT parents.id AS parents_id, parents.name AS parents_name 
FROM parents JOIN "Parent_images" AS "Parent_images_1" ON parents.id = "Parent_images_1".parent_id JOIN children ON children.id = "Parent_images_1".child_id 
WHERE lower(parents.name) LIKE lower(?) OR lower(children.name) LIKE lower(?)

The subquery子查询

q = (session.query(Parent)
            .filter(sa.or_(Parent.name.ilike('%foo%'),
                            Parent.colours.any(Child_s3.name.ilike('%foo%')))))

generates this SQL:生成此 SQL:

SELECT parents.id AS parents_id, parents.name AS parents_name            
FROM parents                                                                                                                        
WHERE lower(parents.name) LIKE lower(?) OR (EXISTS (SELECT 1                                                                        
FROM "Parent_images", children                                                                                                      
WHERE parents.id = "Parent_images".parent_id AND children.id = "Parent_images".child_id AND lower(children.name) LIKE lower(?)))

The script produces this output from the sample data:该脚本从示例数据中生成此 output:

Join
Parent(name=baz) [Child_s3(name=foobar)]
Parent(name=boofoo) [Child_s3(name=spam)]

Subquery
Parent(name=boofoo) [Child_s3(name=spam)]
Parent(name=baz) [Child_s3(name=foobar)]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM