I am trying to find out if it is safe to do the following:
items = MyModel.objects.filter(q)
if items:
list(items)
I know that the QuerySet is being evaluated in the if statement, checking if the database returns an empty set. But I want to know if the value of that evaluation is reused when doing list(items). Is the QuerySet being evaluated here too, or is it using the previously evaluated one?
I know I could just do the following:
items = MyModel.objects.filter(q).all()
if items:
list(items)
And this would result in one evaluation, but I am just trying to find out the behavior the first variation has. I have gone throught these pieces of doc (1 2) but couldn't really find a straight answer to this matter.
No. Both will not execute twice (internally .filter(), .all() and .filter().all() are same). You can check it in django shell itself
from django.db import connection
print connection.queries
items = MyModel.objects.filter(q).all() #or MyModel.objects.filter(q)
if items:
list(items)
print connection.queries
Then here is the magic of .all()
queryset = MyModel.objects.all() #no db hit, hit=0
print list(queryset) #db hit, hit=1
print list(queryset) #no db hit, hit=1
print list(queryset.all()) #db hit, hit=2
print list(queryset.all()) #db hit, hit=3
That means .all() on an evaluated queryset will force db hit.
When a QuerySet is evaluated, it typically caches its results. If the data in the database might have changed since a QuerySet was evaluated, you can get updated results for the same query by calling all() on a previously evaluated QuerySet
It will reuse it's cache, because when you do
if items:
It will call __bool__ method
def __bool__(self):
self._fetch_all()
return bool(self._result_cache)
So as you see inside __bool__ it does call _fetch_all. Which caches data
def _fetch_all(self):
if self._result_cache is None:
self._result_cache = list(self.iterator())
if self._prefetch_related_lookups and not self._prefetch_done:
self._prefetch_related_objects()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With