#23662: QuerySet __nonzero__, __len__ cause queryset evaluation
-------------------------------------+-------------------------------------
Reporter: smishlayev | Owner: nobody
Type: | Status: new
Cleanup/optimization | Version: 1.7
Component: Database layer | Resolution:
(models, ORM) | Triage Stage:
Severity: Normal | Unreviewed
Keywords: | Needs documentation: 0
Has patch: 1 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 1
Easy pickings: 0 |
-------------------------------------+-------------------------------------
Old description:
> Current implementation:
> https://github.com/django/django/blob/master/django/db/models/query.py
>
> {{{
> class QuerySet(object):
> ...
> def __nonzero__(self):
> self._fetch_all()
> return bool(self._result_cache)
> ...
> def __len__(self):
> self._fetch_all()
> return len(self._result_cache)
> }}}
>
> These methods call self._fetch_all(), thus evaluating the queryset.
> Although, this behaviour is documented
> (https://docs.djangoproject.com/en/1.7/ref/models/querysets/#when-
> querysets-are-evaluated), it is not obvious.
>
> It seems logical to evaluate queryset, when casting it to a list() or
> iterating over it, but these particular cases have nothing to do with the
> queryset contents. There exist specific lazy methods (QuerySet.exists()
> and QuerySet.count() respectively) which, IMHO, should be used for the
> magic method implementation.
>
> If I already have fetched the results of a queryset, I'm okay to call
> __len__() on them, but if they haven't been retrieved yet, I'd rather use
> SQL COUNT() instead. That is exactly, what QuerySet.count() does. The
> same goes for the __nonzero__() and exists().
New description:
Current implementation:
https://github.com/django/django/blob/master/django/db/models/query.py
{{{
class QuerySet(object):
...
def __nonzero__(self):
self._fetch_all()
return bool(self._result_cache)
...
def __len__(self):
self._fetch_all()
return len(self._result_cache)
}}}
These methods call `self._fetch_all()`, thus evaluating the queryset.
Although, this behaviour is
[https://docs.djangoproject.com/en/1.7/ref/models/querysets/#when-
querysets-are-evaluated documented], it is not obvious.
It seems logical to evaluate queryset, when casting it to a `list()` or
iterating over it, but these particular cases have nothing to do with the
queryset contents. There exist specific lazy methods (`QuerySet.exists()`
and `QuerySet.count()` respectively) which, IMHO, should be used for the
magic method implementation.
If I already have fetched the results of a queryset, I'm okay to call
`__len__()` on them, but if they haven't been retrieved yet, I'd rather
use `SQL COUNT()` instead. That is exactly, what QuerySet.count() does.
The same goes for the `__nonzero__()` and `exists()`.
--
Comment (by dfunckt):
Ditto
--
Ticket URL: <https://code.djangoproject.com/ticket/23662#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/068.4ca5577c48447adfd28d6fc208c19820%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.