Условные аннотации в Джанго - PullRequest
4 голосов
/ 31 августа 2010

Я получил простое требование (не простую реализацию) и выяснил, как его достичь, не совершая многократных обращений к дБ и без .extra() в наборе запросов.

Task:
  name = xxx
  status = models.IntegerField(choices=some_choices)
  project = ForeignKey(Project)

Project:
  name = xxx
  code = xxx

Проекты содержат Задачи, получившие различные статусы. (Предположим, статус = 3 завершен) Теперь я хочу перечислить все проекты с их общими и завершенными задачами, как показано ниже

  1. Проект 1, total_tasks = 5, завершено_tasks = 2
  2. Проект 1, total_tasks = 2, завершено_tasks = 1

Я могу получить total_tasks с аннотацией, но не complete_tasks, так как это требует условия в аннотации. Есть ли в любом случае, чтобы сделать это?

Ответы [ 3 ]

5 голосов
/ 20 октября 2015

Эта функция нова в Django 1.8.

См .: https://docs.djangoproject.com/en/1.8/ref/models/conditional-expressions/

Это возможно:

from django.db.models.aggregates import Count
from django.db.models.expressions import F, Value, Case, When

projects = Project.objects.annotate(
        total_tasks=Count('task__pk'),
        completed_tasks=Count(Case(
           When(status=3, then=F('task__pk')),
           output_field=IntegerField()
        ))).all()
0 голосов
/ 03 сентября 2010

Не знаю, поможет ли это, но вы можете написать свои собственные объекты аннотаций.Я только что сделал это, хотя без условной части.Я основал свое решение на этой ссылке: http://www.voteruniverse.com/Members/jlantz/blog/conditional-aggregates-in-django

, но не использовал пример там.Вместо этого я посмотрел на код django для агрегатов и расширил сами объекты Sum и Count.

0 голосов
/ 31 августа 2010

Если вы не возражаете против дополнительных запросов, вы можете получить два набора запросов вместо одного.Первый может подсчитать общий счет, а второй может отфильтровать tasks_status и, таким образом, завершить подсчет.

from django.db.models import Count
all_projects = Project.objects.all()
total_counts = all_projects.annotate(count = Count('tasks'))
completed_counts = all_projects.filter(tasks_status = 3).annotate(count = Count('tasks'))
...