#30655 closed Bug (wontfix)
len(queryset) and queryset.count() return different results.
Reported by: | Sander Kleijwegt | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
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 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)>]>
Change History (5)
comment:1 by , 5 years ago
Description: | modified (diff) |
---|---|
Version: | 2.0 → 2.2 |
comment:2 by , 5 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|---|
Resolution: | → wontfix |
Status: | new → closed |
Summary: | len(queryset) and queryset.count() return different results → len(queryset) and queryset.count() return different results. |
Version: | 2.2 → master |
comment:3 by , 5 years ago
So you are confirming that contrary to what the documentation says, you should NOT always use count() instead of len() ?
comment:4 by , 5 years ago
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.
comment:5 by , 2 years ago
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'))
Thanks for this report, but
QuerySet.count()
andlen(QuerySet)
can return different results.count()
callsSELECT COUNT(*)
(as described in docs) without taking ordering into account, so in your case it returns the number ofBar
's. On the other handlen()
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.