我当前在Post
模型上具有以下属性:
@property
def compliments(self):
compliments_by_kind = list(
self.compliment_set.values(
'kind'
).annotate(
amount=Count('kind')
).values(
'kind',
'amount'
)
)
for compliment_by_kind in compliments_by_kind:
compliment_by_kind['last_giver'] = self.compliment_set.filter(
kind=compliment_by_kind['kind']
).order_by(
'created'
).last().giver.name
return compliments_by_kind
这将返回以下列表数据结构:
[
{
'kind': 'unique',
'amount': 3,
'last_giver': 'Person 1'
},
{
'kind': 'fresh',
'amount': 2,
'last_giver': 'Person 2'
},
{
'kind': 'concept',
'amount': 3,
'last_giver': 'Person 3'
},
{
'kind': 'lines',
'amount': 1,
'last_giver': 'Person 4'
}
]
数据本身没有问题。在循环中执行查询的性能根本不合适
然而,循环方法——不是很有效——对于每种类型(总共有6个),在一个查询之上还有6个查询来获取Count
注释。因此,这确实会影响serialization
阶段的性能
有谁知道如何根据“created
”属性根据“种类”的顺序为最新的Compliment
“giver.name
”执行annotation
操作…即,最后一个给予“种类”独特等称赞的人
以下是Compliment
模型:
class Compliment(TimeStampedModel):
giver = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
related_name="giver",
)
receiver = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
related_name="receiver",
)
post = models.ForeignKey('blog.post', on_delete=models.CASCADE)
kind = models.CharField(choices=COMPLIMENTS_CHOICES, max_length=15)
更新:利用威廉的绝妙建议,我的解决方案是:
@property
def compliments(self):
from django.contrib.auth import get_user_model
from django.db.models import OuterRef, Subquery
compliments_by_kind = list(
self.compliment_set.values(
'kind'
).annotate(
amount=Count('kind'),
first_name=Subquery(
get_user_model().objects.filter(
giver__artwork_id=self.pk,
giver__kind=OuterRef('kind')
).values('first_name').order_by('-giver__created')[:1]
),
last_name=Subquery(
get_user_model().objects.filter(
giver__artwork_id=self.pk,
giver__kind=OuterRef('kind')
).values('last_name').order_by('-giver__created')[:1]
),
)
)
return compliments_by_kind
通过使用
Subquery
,您可以在同一查询中获得last_giver
(从而避免了N+1问题):话虽如此,正如评论中所讨论的,^{} [Django-doc]是“反向”关系的名称,因此是获得用户给予或收到的称赞的人。因此,最好将其重命名为:
然后查询如下所示:
相关问题 更多 >
编程相关推荐