#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.

Reply via email to