The original problem caused by quite awkward cycling models reference:
# A -> B -> A
class A:
b = models.ForeignKey('B', null=True, blank=True)
class B:
a = models.ForeignKey('A')
Now, when I'm trying to annotate query, it always uses GROUP BY a's id from LEFT OUTER JOIN ( T3.id in the example below) instead of a.id.
Example:
A.objects.select_related('b', 'b__a').annotate(reviews=Count('reviews'))
Generated SQL:
SELECT
`a`.`id`,
`b`.`id`,
T3.`id`,
FROM
`a`
LEFT OUTER JOIN
`b` ON (`a`.`b_id` = `b`.`id`)
LEFT OUTER JOIN
`a` T3 ON (`b`.`a_id` = T3.`id`)
WHERE
`a`.`id` IN (1, 2, 3, 4, 5)
GROUP BY T3.`id`
ORDER BY NULL;
I know I can do next things:
- Change model not to do cycling reference (unfortunately can't do that right now)
- Can use .extra() instead of annotations (I'd try to avoid it)
- Remove .select_related() call (can't do due to performance issues)
UPD: Using GROUP BY T3.id will exclude results, where a.b == None
The best solution for me would be just specifying correct field in GROUP BY clause, but I don't know how. Is it possible? Is there any other way to fix the problem? Thanks.
Opened Django compiler:
So, collapse_group_by function doesn't stop looking for pk even it's found already, that's why grouping by is done by T3.id instead of a.id (and thus I have missing results). To fix the problem, breakpoint is required inside for loop (marked in comments).
UPD: the issue already fixed in Django 1.8.2 version https://code.djangoproject.com/ticket/24748