[Django] #30655: len(queryset) and queryset.count() return different results

19 views
Skip to first unread message

Django

unread,
Jul 23, 2019, 5:21:36 AM7/23/19
to django-...@googlegroups.com
#30655: len(queryset) and queryset.count() return different results
-----------------------------------------+------------------------
Reporter: Big4SMK | Owner: nobody
Type: Bug | Status: new
Component: Uncategorized | Version: 2.0
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-----------------------------------------+------------------------
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.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.

Django

unread,
Jul 23, 2019, 5:47:11 AM7/23/19
to django-...@googlegroups.com
#30655: len(queryset) and queryset.count() return different results
----------------------------------+--------------------------------------
Reporter: Sander Kleijwegt | Owner: nobody
Type: Bug | Status: new
Component: Uncategorized | Version: 2.2
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
----------------------------------+--------------------------------------
Changes (by Sander Kleijwegt):

* 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>

Django

unread,
Jul 23, 2019, 6:26:49 AM7/23/19
to django-...@googlegroups.com
#30655: len(queryset) and queryset.count() return different results.
-------------------------------------+-------------------------------------
Reporter: Sander Kleijwegt | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution: wontfix

Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by felixxm):

* 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>

Django

unread,
Jul 23, 2019, 6:46:04 AM7/23/19
to django-...@googlegroups.com
#30655: len(queryset) and queryset.count() return different results.
-------------------------------------+-------------------------------------
Reporter: Sander Kleijwegt | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution: wontfix
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

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>

Django

unread,
Jul 23, 2019, 7:48:06 AM7/23/19
to django-...@googlegroups.com
#30655: len(queryset) and queryset.count() return different results.
-------------------------------------+-------------------------------------
Reporter: Sander Kleijwegt | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution: wontfix
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

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>

Django

unread,
Sep 15, 2022, 5:46:40 AM9/15/22
to django-...@googlegroups.com
#30655: len(queryset) and queryset.count() return different results.
-------------------------------------+-------------------------------------
Reporter: Sander Kleijwegt | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: dev

(models, ORM) |
Severity: Normal | Resolution: wontfix
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

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>

Reply all
Reply to author
Forward
0 new messages