python SQLAlchemy联合加载筛选器列

cgyqldqp  于 2023-02-21  发布在  Python
关注(0)|答案(2)|浏览(111)

嗨,我想用joinedload对我的查询做一个过滤器。但是我似乎不能让它工作。下面是我的示例查询

result = (
        session.query(Work).
        options(
            joinedload(Work.company_users).
            joinedload(CompanyUser.user)
        ).
        filter(Work.id == 1).
        filter(User.first_name == 'The name').  <<--- I can't get this to work.
        all()
    )

运行此查询时,返回的行比我预期的多。真实的结果应仅返回8行。但在执行此查询时,返回234行,比我预期的多很多

insrf1ej

insrf1ej1#

它不起作用的原因是joinedload(以及所有其他关系加载技术)应该是完全透明的。也就是说,在查询中使用joinedload不应该以任何其他方式影响它,而只是导致填充关系。您应该阅读“连接的渴望加载的禅宗”,它的开头是:
由于联合急切加载看起来与Query.join()的使用有许多相似之处,它经常会在何时以及如何使用它方面产生混淆。理解Query.join()用于更改查询结果,而joinedload()则不遗余力地不更改查询结果这一区别是至关重要的。而是隐藏所呈现的联接的效果以仅允许相关对象存在。
其中一个技巧是为不可用的连接表使用别名。然后,您的查询将在Work和User之间执行隐式交叉连接,从而导致额外的行。因此,为了针对连接表进行过滤,请使用Query.join()

session.query(Work).\
    join(Work.company_users).\
    join(CompanyUser.user).\
    filter(Work.id == 1).\
    filter(User.first_name == 'The name').\
    all()

如果您还需要将eagerloads放在适当的位置,您可以指示Query它已经包含了与contains_eager()的连接:

session.query(Work).\
    join(Work.company_users).\
    join(CompanyUser.user).\
    options(contains_eager(Work.company_users).
            contains_eager(CompanyUser.user)).\
    filter(Work.id == 1).\
    filter(User.first_name == 'The name').\
    all()

注意对contains_eager()的链式调用。

bvn4nwqk

bvn4nwqk2#

好的,我明白了。只是为了那些可能解决同样问题的人,我所做的是将joinedload替换为contains_eager,并添加了一个join。下面是修改代码

result = (
    session.query(Work)
    .join(Work.company_users)
    .join(CompanyUser.user)
    .options(
        contains_eager(Work.company_users)
        .contains_eager(CompanyUser.user)
    )
    .filter(Work.id == 1)
    .filter(User.first_name == 'The name')  # <<--- Now this to works.
    .all()
)

相关问题