I do not see any direct way to do that. Some workarounds I can think of:
Direct iteration (1 query) :
The most direct way, only involve one query. Remember to use iterator so you don't have the full queryset in memory.
for product in Products.objects.filter(category_id__in=[1, 2, 3]).iterator():
# Add some logic to select your six items.
Of course depending on the iteration order it could be time consuming (for instance if all your category 1 items were inserted first). Throwing a random order .order('?')
may help but be careful that it have some caveats (mainly, it's slow).
Query each category (as many queries as categories):
[
p
for category_id in [1, 2, 3]
for p in Products.objects.filter(category_id=category_id)[:2]
]
The result is not a queryset anymore, but that may not matter.
Multiple rounds (2 queries if you want the first 2 of each):
Get the first of each categories, exclude them and then get the second ones.
ids = [1, 2, 3]
items = list(Products.objects.filter(category_id__in=ids).distinct('category'))
items += list(Products.objects.filter(category_id__in=ids).exclude(
id__in=[i.id for i in items],
).distinct('category'))
Same caveat that it's a list and not a queryset anymore and also see the limitations on distinct(*field)
.