假设我有一个非常基本的用户模型,包括名称和年龄:
class User(models.Model):
name = CharField() # e.g. John Smith
age = IntegerField() # e.g. 21
我想过滤用户 18+ y/o,并为每个人添加一个特殊属性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
。这与带有to_attr的 annotate(( 或 prefetch_related(( 非常相似,但不完全一样。
如果可能的话,我也希望避免使用原始SQL。
谢谢。
我找到了一篇博客文章,做了一些与我需要的非常相似的事情,并且......亲爱的上帝...
>>> 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。