Models:
{{{
class Bar(models.Model):
pass
class Foo(models.Model):
fooint = models.IntegerField()
foobar = models.ForeignKey(Bar, related_name='foos',
on_delete=models.CASCADE)
}}}
Shell Output:
{{{
>>> import django
>>> django.__version__
'2.0.4'
>>> from foobar.models import Foo, Bar
>>> bar = Bar.objects.create()
>>> foo1 = Foo.objects.create(fooint=1, foobar=bar)
>>> foo2 = Foo.objects.create(fooint=2, foobar=bar)
>>> Bar.objects.all().order_by('foos__fooint').count()
1
>>> len(Bar.objects.all().order_by('foos__fooint'))
2
>>> Bar.objects.all().order_by('foos__fooint')
<QuerySet [<Bar: Bar object (1)>, <Bar: Bar object (1)>]>
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30655>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* version: 2.0 => 2.2
Old description:
New description:
According to the queryset.count() documentation "you should always use
count() rather than loading all of the record into Python objects and
calling len() on the result" (see
[https://docs.djangoproject.com/en/2.0/ref/models/querysets/#count here]),
which seems to imply that the results of both functions should always be
identical. Here is a simple example that shows the contrary.
Models:
{{{
class Bar(models.Model):
pass
class Foo(models.Model):
fooint = models.IntegerField()
foobar = models.ForeignKey(Bar, related_name='foos',
on_delete=models.CASCADE)
}}}
Shell Output:
{{{
>>> import django
>>> django.__version__
'2.2.3'
>>> from foobar.models import Foo, Bar
>>> bar = Bar.objects.create()
>>> foo1 = Foo.objects.create(fooint=1, foobar=bar)
>>> foo2 = Foo.objects.create(fooint=2, foobar=bar)
>>> Bar.objects.all().order_by('foos__fooint').count()
1
>>> len(Bar.objects.all().order_by('foos__fooint'))
2
>>> Bar.objects.all().order_by('foos__fooint')
<QuerySet [<Bar: Bar object (1)>, <Bar: Bar object (1)>]>
}}}
--
--
Ticket URL: <https://code.djangoproject.com/ticket/30655#comment:1>
* status: new => closed
* component: Uncategorized => Database layer (models, ORM)
* version: 2.2 => master
* resolution: => wontfix
Comment:
Thanks for this report, but `QuerySet.count()` and `len(QuerySet)` can
return different results.
`count()` calls `SELECT COUNT(*)` (as described in
[https://docs.djangoproject.com/en/2.2/ref/models/querysets/#count docs])
without taking ordering into account, so in your case it returns the
number of `Bar`'s. On the other hand `len()` evaluates query with ordering
by related table (one to many) that's why it returns a different number.
This behavior is in Django since 9c52d56f6f8a9cdafb231adf9f4110473099c9b5.
--
Ticket URL: <https://code.djangoproject.com/ticket/30655#comment:2>
Comment (by Sander Kleijwegt):
So you are confirming that contrary to what the documentation says, you
should NOT always use count() instead of len() ?
--
Ticket URL: <https://code.djangoproject.com/ticket/30655#comment:3>
Comment (by felixxm):
Nope. You should use `count()`, but you should know what you want to
count. If you want to count the no. of `Bar`'s then
`Bar.objects.all().count()` is a obvious choice and it's natural for me
that ordering doesn't impact this value. If you want to count the no. of
`Foo`'s then use `Foo.objects.all().count()`, etc.
--
Ticket URL: <https://code.djangoproject.com/ticket/30655#comment:4>
Comment (by Huub Bouma):
I think it's crazy that an order_by changes the amount of records in the
resulting queryset..
Here's a workaround to achieve the sorting without duplicate records in
the queryset:
{{{
from django.db.models import Max
Bar.objects.all().annotate(ordered_fooint=Max('foos__fooint')).order_by('ordered_fooint'))
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30655#comment:5>