在 Django 中使用 Q 对象进行内连接

问题描述 投票:0回答:1

我正在我的项目中自定义模型的管理更改列表页面。

此模型包含多对多字段,我想允许多选过滤。

我使用了 Django Admin Multi Select Filter package 来执行此操作,但我注意到 Django

__in
查找中的默认行为是包含而不是排他。

假设我有一个与 M2M 对象 1 和 2 关联的对象 A,以及与 M2M 对象 2 和 3 关联的对象 B。如果我进行以下查询

Model.objects.filter(m2m_model__in=[1,2])
我将同时检索对象 A 和 B,因为搜索将使用满足以下条件:

Index Cond: (models_model_m2mfield.model_id = ANY ('{1,2}'::bigint[]))

我能够通过执行以下操作来自定义搜索行为:

            for choice in choices:
                queryset = queryset.filter(**{self.lookup_kwarg: choice})

这会生成内部联接并返回我正在等待的值(仅匹配每个选项的对象)。

INNER JOIN "models_model_m2mfield" ON ("models_m2mmodel"."id" = "models_model_m2mfield"."m2mfield_id") INNER JOIN "models_model_m2mfield" T4 ON ("models_m2mmodel"."id" = T4."m2mfield_id") WHERE ("models_model_m2mfield"."model_id" = 4 AND T4."model_id" = 5)

我尝试使用 Q 对象来获得相同的结果,但我无法使其工作。使用 Q 类是否可以实现相同的行为?

python django django-orm
1个回答
0
投票

是否可以使用 Q 类实现相同的行为?

,您不能使用单个

Q
对象来执行此操作。

如果您在同一模型上使用两个(或更多)

.filter(…)
子句[Django-doc] JOIN,则会导致同一个表上出现单独的
LEFT OUTER JOIN
。这就是为什么这会起作用。这就是我们所需要的,但它可以,特别是如果没有很好地优化,在一个不是很有效的大型查询中。

但是,我们可以做的是使用

.alias(…)
 [Django-doc]
.filter(…)
来检查匹配数是否是所需的数量,因此:

from django.db.models import Count

data = [1, 2]
Model.objects.alias(
    nmatch=Count('m2m_model', filter=Q(m2m_model__in=data), distinct=True)
).filter(nmatch=len(set(data)))

因此,我们首先计算匹配的数量,然后将该数量限制为

data
中唯一匹配的数量。

© www.soinside.com 2019 - 2024. All rights reserved.