Django ORM优化-通过计数进行注释以及注释过滤器的最后一个条目

问题描述 投票:1回答:1

我目前在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注释。因此,这确实会影响[ C0]阶段。

[谁会知道如何根据“种类”的“ serialization”属性的顺序,对最新的annotationCompliment”执行giver.name ...,即最后给出的人称赞“独特”等

这里是created模型:

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)
python django django-orm
1个回答
2
投票
您可以通过使用@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 在同一查询中获得last_giver(从而避免了[[N + 1问题
© www.soinside.com 2019 - 2024. All rights reserved.