如何使用Django的ORM使用子查询检索聚合?

时间:2014-11-25 14:44:47

标签: python django orm django-queryset django-orm

鉴于这些模型:

from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models


class UserProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)
    related_to = models.ForeignKey(
        settings.AUTH_USER_MODEL, blank=True, null=True, related_name='profile')
    # a few other fields


class Metric(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, verbose_name='user', related_name='metrics')
    value = models.FloatField(verbose_name='value')
    target = models.FloatField(verbose_name='target value', default=0)
    date_measured = models.DateField(verbose_name='date measured')

用户可以与另一个用户相关,作为父子关系。

如何最好地检索所有用户的孩子的指标总和(总和) 使用ORM的目标值和总和?

与此RAW SQL类似的东西:

SELECT `auth_user`.`id`,
       `auth_user`.`username`,
       `mf`.`meta`,
       `mf`.`value`
FROM `auth_user`
LEFT JOIN
  (SELECT `metric`.`user_id`,
          SUM(`metric`.`meta`) AS `meta`,
          SUM(`metric`.`value`) AS `value`
   FROM `metric`
   INNER JOIN `userprofile` ON (`userprofile`.`user_id` = `metric`.`user_id`)
   GROUP BY `metric`.`user_id`) mf ON (`auth_user`.`id` = mf.`user_id`)
WHERE `auth_user`.`id` = 1

这不起作用(它不会产生用户的指标聚合):

items = get_user_model().objects \
    .filter(userprofile__related_to__id=1) \
    .annotate(
        meta=Sum('metric__meta'),
        value=Sum('metric__value'),
    ) \

1 个答案:

答案 0 :(得分:0)

如果您将related_to重命名为parent_user并将profile重命名为child_profiles,则可能会更容易想到这一点:

class UserProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)
    parent_user = models.ForeignKey(
        settings.AUTH_USER_MODEL, blank=True, null=True, related_name='child_profiles')
    ...

然后,你可以这样做:

metric_sums = Metric.objects.filter(
    user__userprofile__parent_user_id=1).annotate(
        meta=Sum('meta'),
        value=Sum('value'))