django queryset union 不能仅使用
Posted
技术标签:
【中文标题】django queryset union 不能仅使用【英文标题】:django queryset union not working with only 【发布时间】:2021-02-02 03:03:29 【问题描述】:我有 2 个querysets
,我正在对它们应用union
,但奇怪的是当我使用only
时,它会从数据库中选择所有字段,而当我使用values
时,它只会选择给定的字段。
这是从Physician
表中选择所有字段
doctors_models.Physician.objects.filter(
appointments__member=self.context['member']
).union(doctors_models.Physician.objects.filter(
appointments__booked_by=self.context['member']
)).only('id', 'name_prefix', 'first_name', 'middle_name', 'last_name', 'name_suffix')
但是
这是从Physician
表中仅选择指定字段
doctors_models.Physician.objects.filter(
appointments__member=self.context['member']
).union(doctors_models.Physician.objects.filter(
appointments__booked_by=self.context['member']
)).values('id', 'name_prefix', 'first_name', 'middle_name', 'last_name', 'name_suffix')
但是,这也是只选择指定的字段,但我为什么要定义字段 2 次。
doctors_models.Physician.objects.filter(
appointments__member=self.context['member']
).only('id', 'name_prefix', 'first_name', 'middle_name', 'last_name', 'name_suffix').union(
doctors_models.Physician.objects.filter(
appointments__booked_by=self.context['member']
).only('id', 'name_prefix', 'first_name', 'middle_name', 'last_name', 'name_suffix'))
【问题讨论】:
如果你有联合,两个部分必须有相同数量的字段 具有相同的字段。 不,它不仅限制了 SELECT 查询中使用的字段,您也可以通过使用 Q 对象在单个查询中正确执行此操作,Willem 已经详细解释过 【参考方案1】:但是,这也是只选择指定的字段,但为什么我要定义字段 2 次?
因为SELECT
语句的列数及其类型应该匹配,正如documentation on .union(…)
中指定的那样:
只要
SELECT
列表在所有QuerySet
s 中都相同,传递不同的模型就可以工作(至少 类型,名称无关紧要只要类型的顺序相同)。在这种情况下,您必须使用来自QuerySet
方法中的第一个QuerySet
的列名应用于生成的QuerySet
。
话虽如此,请不要首先使用.union(…)
。您可以通过将这两个条件包装在 Q
对象中并将它们与“或”组合在一起来合并这两个条件:
from django.db.models import Q
doctors_models.Physician.objects.filter(
Q(appointments__member=self.context['member']) |
Q(appointments__booked_by=self.context['member'])
).only('id', 'name_prefix', 'first_name', 'middle_name', 'last_name', 'name_suffix')
此外,使用.only(…)
[Django-doc] 或.defer(…)
[Django-doc] 仅适用于包含大量数据的列。对于“小”的列,往往不会有太大的影响,而且万一以后需要这些字段,甚至会导致N+1个问题。
【讨论】:
1. OR 查询将导致“不会使用索引”,这就是使用联合的原因。 2. 使用only
,这样它就不会获取所有不必要的字段。 3. 你说联合在两个查询中的列相同并且它们在我的查询中时有效。您看到不同的列了吗?
@SHIVAMJINDAL:如果您分别对两个列进行取消索引,通常它将使用两个索引。通常在内部数据库将其重写为 UNION,但优点是您不必自己编写两个 SELECT
语句:orafaq.com/tuningguide/logical%20operators.html
@Willen 这是写在mysql自动将OR查询转换为联合的地方吗
@SHIVAMJINDAL:一个好的数据库会收集统计数据并根据统计数据制定查询计划。如果您进行查询并且数据库期望返回大量行,它不会使用索引,那么扫描表会更有效(因为即使它使用索引,稍后它也必须扫描以返回记录)。查询计划基于selectivity of the indexes。因此,这意味着如果appointments
关系中不同的booked_by
s 的数量很少,它将不会使用索引。
@SHIVAMJINDAL:因此,查询计划不仅取决于查询,还取决于数据库期望检索的记录数。如果选择性为 0.7,则期望检索大量记录。以上是关于django queryset union 不能仅使用的主要内容,如果未能解决你的问题,请参考以下文章
queryset,union,order_by 在带注释的字段上
需要根据找到的 Q 对象来注释 Django querySet
Django queryset - 在对象上应用过滤器时仅返回匹配的多记录