【问题标题】:Django: how to add a custom attribute to each element of queryset without N+1 request?Django:如何在没有 N+1 请求的情况下为查询集的每个元素添加自定义属性?
【发布时间】:2018-01-26 12:13:54
【问题描述】:

假设我有一个非常基本的用户模型,包含姓名和年龄:

class User(models.Model):
    name = CharField()  # e.g. John Smith
    age = IntegerField()  # e.g. 21

我想过滤 18 岁以上的用户,并为每个用户添加一个特殊属性 namesakes(例如,对于 "John Smith",它类似于 ["John Williams", "John for Neumann", ...])。

我知道,如何在 N+1 个请求中做到这一点:

for user in User.objects.filter(age__gt=18):
    user.namesakes = User.objects.filter(name__startswith=user.name.split()).\
                                   all()

但是我如何在一个请求中做到这一点?理想情况下,对于查询集中的每个User 对象,我想创建一个包含同名查询集的自定义属性namesakes。这与 annotate() 或 prefetch_related() with to_attr 所做的非常相似,但不完全一样。

如果可能,我也希望避免使用原始 SQL。

谢谢。

【问题讨论】:

标签: sql django


【解决方案1】:

我找到了一个blog post,正在做一些与我需要的非常相似的事情......亲爱的上帝......

>>> from django.db.models import F, Q, Case, IntegerField, Sum, Value, When
>>> from django.db.models.functions import Coalesce
>>> pizzas = Pizza.objects.annotate(
...     uses_name_of_another_pizza_as_name_prefix=Coalesce(
...         Sum(
...             Case(
...                 When(
...                     Q(
...                         ~Q(pk=F('category__pizzas')) &
...                         Q(name__startswith=F('category__pizzas__name'))
...                     ),
...                     then=Value(1)
...                 ),
...                 output_field=IntegerField(),
...             ),
...         ),
...         0,
...     ),
... )
>>> [p, p.uses_name_of_another_pizza_as_name_prefix for p in pizzas]
[
    (<Pizza: Hawaiian>, 0),
    (<Pizza: Hawaiian King>, 1),
    (<Pizza: Pepperoni>, 0),
]

不过,它并不能满足我的精确需求。所以,我更喜欢使用原始 SQL。

【讨论】:

  • 不错!我见过Concat 的一些东西,但不是Coalesce。也就是说,如果我理解正确,对于您的用例,您需要在数据库中使用“约翰”(没有姓氏)来查找约翰的同名,对吧?
  • @PauloAlmeida 是的,这篇文章并没有完全解决我的问题 - 它计算同名,但不返回它们的列表。 Coalesce 在这里并没有真正发挥重要作用——我相信它只是提供了一个 0 默认值。不幸的是,我仍然没有找到一个自我加入的好方法:)
猜你喜欢
  • 2021-08-14
  • 2021-05-22
  • 2017-05-02
  • 2020-01-30
  • 2011-11-29
  • 2017-03-07
  • 1970-01-01
  • 1970-01-01
  • 2015-11-30
相关资源
最近更新 更多