Próbuję się dowiedzieć, czy tak jest bezpieczny wykonać następujące czynności:
items = MyModel.objects.filter(q)
if items:
list(items)
Wiem, że QuerySet
jest oceniany w if
oświadczenie, sprawdzanie, czy baza danych zwraca pusty zestaw. Ale chcę wiedzieć, czy wartość tej oceny jest ponownie wykorzystywana list(items)
. Jest QuerySet
bycie tutaj również ocenianym, czy też jest to wykorzystanie wcześniej ocenianego?
Wiem, że mógłbym wykonać następujące czynności:
items = MyModel.objects.filter(q).all()
if items:
list(items)
A to skutkowałoby jedną oceną, ale staram się tylko dowiedzieć, jakie zachowanie ma pierwsza odmiana. Przejrzałem te fragmenty dokumentu (1 2), ale nie mogłem znaleźć prostej odpowiedzi w tej sprawie.
Odpowiedzi:
2 dla odpowiedzi № 1Nie. Obie nie będą wykonywane dwukrotnie (wewnętrznie .filter()
, .all()
i .filter().all()
Są takie same). Możesz to sprawdzić w django shell
samo
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
Oto magia .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
To znaczy .all()
na ewaluowanym zestawie zapytań wymusi działanie db.
Gdy kwerenda jest oceniana, zwykle buforujejego wyniki. Jeśli dane w bazie danych mogły ulec zmianie od czasu, gdy został oceniony obiekt QuerySet, można uzyskać zaktualizowane wyniki dla tego samego zapytania, wywołując metodę all () w uprzednio oszacowanym QuerySet
1 dla odpowiedzi nr 2
Wykorzysta to pamięć podręczną, ponieważ kiedy to zrobisz
if items:
Zadzwoni __bool__
metoda
def __bool__(self):
self._fetch_all()
return bool(self._result_cache)
Tak jak widzisz w środku __bool__
to dzwoni _fetch_all
. Które buforuje dane
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()
0 dla odpowiedzi № 3
Dla lepszej wydajności:
items = MyModel.objects.filter(q) # no evaluation
if items.exists(): # evaluates, hits db
# do stuff here # further actions evaluates, hits db