Учитывая набор запросов, я добавляю счет связанных объектов (ModelA) со следующим:
qs = User.objets.all()
qs.annotate(modela__count=models.Count('modela'))
Однако есть ли способ подсчитать ModelA, который соответствует только критериям? Например, подсчитайте ModelA, где deleted_at имеет значение null?
Я пробовал два решения, которые не работают должным образом.
1) По предложению @knbk используйте фильтр, прежде чем комментировать.
qs = User.objects.all().filter(modela__deleted_at__isnull=True).annotate(modela__count=models.Count('modela', distinct=True))
Вот упрощенная версия запроса, созданного django:
SELECT COUNT(DISTINCT "modela"."id") AS "modela__count", "users".*
FROM "users"
LEFT OUTER JOIN "modela" ON ( "users"."id" = "modela"."user_id" )
WHERE "modela"."deleted_at" IS NULL
GROUP BY "users"."id"
Проблема возникает из предложения WHERE. В самом деле, есть ЛЕВОЕ ПРИСОЕДИНЕНИЕ, но более поздние условия WHERE заставили его быть простым JOIN. Мне нужно вывести условия в предложение JOIN, чтобы оно работало по назначению.
Итак, вместо
LEFT OUTER JOIN "modela" ON ( "users"."id" = "modela"."user_id" )
WHERE "modela"."deleted_at" IS NULL
Мне нужно следующее, которое работает, когда я выполняю его непосредственно в простом SQL.
LEFT OUTER JOIN "modela" ON ( "users"."id" = "modela"."user_id" )
AND "modela"."deleted_at" IS NULL
Как я могу изменить набор запросов, чтобы получить это, не выполняя необработанный запрос?
2) Как и другие, я мог бы использовать условную агрегацию.
Я попробовал следующее:
qs = User.objects.all().annotate(modela__count=models.Count(Case(When(modela__deleted_at__isnull=True, then=1))))
который превращается в следующий SQL-запрос:
SELECT COUNT(CASE WHEN "modela"."deleted_at" IS NULL THEN 1 ELSE NULL END) AS "modela__count", "users".*
FROM "users" LEFT OUTER JOIN "modela" ON ( "users"."id" = "modela"."user_id" )
GROUP BY "users"."id"
Таким образом, я получаю всех пользователей (поэтому LEFT JOIN работает правильно), но я получаю "1" (вместо 0) для modela__count
для всех пользователей, у которых вообще нет модели ModelA.
Почему я получаю 1, а не 0, если нечего подсчитывать?
Как это можно изменить?