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 列表在所有 QuerySets 中都相同,传递不同的模型就可以工作(至少 类型,名称无关紧要只要类型的顺序相同)。在这种情况下,您必须使用来自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_bys 的数量很少,它将不会使用索引。 @SHIVAMJINDAL:因此,查询计划不仅取决于查询,还取决于数据库期望检索的记录数。如果选择性为 0.7,则期望检索大量记录。

以上是关于django queryset union 不能仅使用的主要内容,如果未能解决你的问题,请参考以下文章

queryset,union,order_by 在带注释的字段上

需要根据找到的 Q 对象来注释 Django querySet

Django queryset - 在对象上应用过滤器时仅返回匹配的多记录

Cassandra 用户定义类型上的 Django Queryset 引发类型错误

重修课程day61(django之补充)

Django REST 仅列表(无详细信息)