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

--

Comment (by dfunckt):

 Edited bug description to properly format example code

--
Ticket URL: <https://code.djangoproject.com/ticket/23662#comment:2>
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 django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/068.081d2577ca6981e5874a4467291e9ef4%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to