How to print object's values with "annotate()" and "for loop" in ascending order?
I have Category
and Product
models below. *I use Django 3.2.16:
# "models.py"
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=20)
class Product(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
Then, when running test
view to print id
, name
and product__count
with annotate() and index as shown below:
# "views.py"
from .models import Category
from django.http import HttpResponse
from django.db.models import Count
def test(request):
qs = Category.objects.annotate(Count('product'))
print(qs[0].id, qs[0].name, qs[0].product__count)
print(qs[1].id, qs[1].name, qs[1].product__count)
print(qs[2].id, qs[2].name, qs[2].product__count)
print(qs[3].id, qs[3].name, qs[3].product__count)
return HttpResponse("Test")
These are printed in ascending order properly as shown below:
1 Fruits 14
2 Vegetables 10
3 Meat 4
4 Fish 3
But, when running test
view to print id
, name
and product__count
with annotate() and for loop as shown below:
# "views.py"
# ...
def test(request):
qs = Category.objects.annotate(Count('product'))
for obj in qs:
print(obj.id, obj.name, obj.product__count)
return HttpResponse("Test")
These are printed in descending order improperly as shown below:
4 Fish 3
2 Vegetables 10
3 Meat 4
1 Fruits 14
[25/Jan/202
In addition, when running test
view to print id
and name
with all() and index as shown below:
# "views.py"
# ...
def test(request):
qs = Category.objects.all()
print(qs[0].id, qs[0].name)
print(qs[1].id, qs[1].name)
print(qs[2].id, qs[2].name)
print(qs[3].id, qs[3].name)
return HttpResponse("Test")
And, when running test
view to print id
and name
with all() and for loop as shown below:
# "views.py"
# ...
def test(request):
qs = Category.objects.all()
for obj in qs:
print(obj.id, obj.name)
return HttpResponse("Test")
These are printed in ascending order properly as shown below:
1 Fruits 14
2 Vegetables 10
3 Meat 4
4 Fish 3
So, how can I print object's values with annotate()
and for loop in ascending order properly?
Without any order by, you can not make any assumptions on the order. When subscripting, and the queryset is not ordered, Django will order by primary key to prevent returning the same record multiple times. You can order with:
def test(request):
qs = Category.objects.annotate(Count('product')).order_by('pk')
for obj in qs:
print(obj.id, obj.name, obj.product__count)
return HttpResponse('Test')