values(...).annotate(...) sinh GROUP BY theo đúng các cột liệt kê trong values() đứng trước annotate().
Thứ tự hai lời gọi quyết định ý nghĩa câu truy vấn:
# gom nhóm theo status: mỗi status một dòng
Order.objects.values('status').annotate(total=Count('id'))
# annotate theo từng dòng, rồi chỉ lấy hai cột: không gom nhóm
Order.objects.annotate(total=Count('item')).values('status', 'total')Vì sao order_by() phá nhóm: cột nào xuất hiện trong ORDER BY cũng buộc phải nằm trong GROUP BY (yêu cầu của SQL). Thêm .order_by('created_at') vào query gom nhóm ở trên là nhóm theo (status, created_at) — mỗi đơn hàng thành một nhóm riêng, total đâu đâu cũng bằng 1.
Cạm bẫy hơn nữa: nếu model có Meta.ordering, ordering đó được áp dụng ngầm và gây đúng lỗi trên mà không thấy dòng order_by nào trong code. Django 3.1 đã bỏ hành vi này, nhưng codebase cũ vẫn dính.
Quy tắc an toàn cho query gom nhóm:
(Order.objects
.order_by() # xoá Meta.ordering trước đã
.values('status')
.annotate(total=Count('id'))
.order_by('-total')) # chỉ sắp xếp theo annotationGọi .order_by() rỗng để xoá ordering mặc định, và chỉ sắp xếp theo chính cột annotate hoặc cột đã có trong values().
Khi nghi ngờ, print(qs.query) và soi mệnh đề GROUP BY.