Często mam ochotę pobrać pierwszy obiekt z zestawu zapytań w Django lub zwrócić, None
jeśli nie ma żadnych. Istnieje wiele sposobów na zrobienie tego, które wszystkie działają. Ale zastanawiam się, który jest najbardziej wydajny.
qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
return qs[0]
else:
return None
Czy to powoduje dwa wywołania bazy danych? To wydaje się marnotrawstwem. Czy to jest szybsze?
qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
return qs[0]
else:
return None
Inną opcją byłoby:
qs = MyModel.objects.filter(blah = blah)
try:
return qs[0]
except IndexError:
return None
Generuje to pojedyncze wywołanie bazy danych, co jest dobre. Wymaga to jednak częstego tworzenia obiektu wyjątku, co wymaga dużej ilości pamięci, gdy wszystko, czego naprawdę potrzebujesz, to banalny test wstępny.
Jak mogę to zrobić za pomocą jednego wywołania bazy danych i bez utraty pamięci z obiektami wyjątków?
len()
Ogólna zasada: jeśli martwisz się minimalizacją zwrotów bazy danych w obie strony, nie używaj zestawu zapytań, zawsze używaj.count()
.first()
ilast()
wygodę metod: docs.djangoproject.com/en/dev/ref/models/querysets/#firstOdpowiedzi:
Django 1,6 (wydany listopad 2013) wprowadził metody wygodę
first()
ilast()
który połknąć otrzymanego wyjątku i powrotuNone
jeżeli nie zwróci queryset obiektów.źródło
first()
ilast()
egzekwowanieORDER BY
klauzuli o zapytaniu. Sprawi, że wyniki będą deterministyczne, ale najprawdopodobniej spowolni zapytanie.Poprawna odpowiedź to
Które mogą być użyte w:
Nie chciałbyś najpierw przekształcić go w listę, ponieważ wymusiłoby to pełne wywołanie bazy danych wszystkich rekordów. Po prostu zrób powyższe, a pociągnie tylko pierwszy. Możesz nawet użyć,
.order_by
aby upewnić się, że otrzymujesz pierwszy, czego chcesz.Pamiętaj, aby dodać
.get()
lub otrzymasz QuerySet, a nie obiekt.źródło
Entry.objects.all()[0]
?źródło
LIMIT 1
do zapytania i nie wiem, czy możesz zrobić coś lepszego niż to. Jednak wewnętrznie__nonzero__
wQuerySet
jest zaimplementowane, ponieważtry: iter(self).next() except StopIteration: return false...
nie ucieka od wyjątku.QuerySet.__nonzero__()
nigdy nie jest wywoływany, ponieważQuerySet
jestlist
sprawdzany przed sprawdzeniem poprawności. Jednak nadal mogą wystąpić inne wyjątki.StopIteration
wyjątek.__iter__
aby uzyskać nowy obiekt iteratora i wywołać jegonext
metodę doStopIteration
wyrzucenia. Tak więc na pewno będzie gdzieś wyjątek;)Teraz w Django 1.9 masz
first()
metodę zestawów zapytań.Jest to lepszy sposób niż
.get()
lub[0]
dlatego, że nie zgłasza wyjątku, jeśli zestaw zapytań jest pusty. Therafore, nie trzeba sprawdzać za pomocąexists()
źródło
Jeśli planujesz często zdobywać pierwszy element - możesz rozszerzyć QuerySet w tym kierunku:
Zdefiniuj model w następujący sposób:
I użyj tego w ten sposób:
źródło
Może to również działać:
jeśli jest pusty, to zwraca pustą listę, w przeciwnym razie zwraca pierwszy element na liście.
źródło
Może tak być
lub
źródło
Powinieneś używać metod django, tak jak istnieje. Możesz go użyć.
źródło
Od wersji django 1.6 możesz używać filter () metodą first () w następujący sposób:
źródło