/ / Ocena Django QuerySet dla .all () - django

Ocena Django QuerySet dla .all () - django

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 № 1

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