Czy jest jakaś funkcja Django, która pozwoli mi pobrać obiekt z bazy danych lub Brak, jeśli nic nie pasuje?
W tej chwili używam czegoś takiego:
foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None
Ale to nie jest zbyt jasne, a mieć wszędzie bałagan.
len(foo)
jest zły : „ Uwaga: nie używaj len () na QuerySets, jeśli chcesz tylko określić liczbę rekordów w zestawie. O wiele wydajniej jest obsłużyć liczenie na poziomie bazy danych za pomocą funkcji SELECT COUNT w języku SQL (), a Django udostępnia metodę count () właśnie z tego powodu. ". Przepisano:foo = foo[0] if foo.exists() else None
first()
: POdpowiedzi:
W Django 1.6 możesz użyć
first()
metody Queryset. Zwraca pierwszy obiekt dopasowany przez zestaw zapytań lub None, jeśli nie ma pasującego obiektu.Stosowanie:
źródło
MultipleObjectsReturned()
nie jest to zgłaszane, jak opisano tutaj . Możesz znaleźć lepsze odpowiedzi tutajfirst()
prace dokładnie tak, jak przypuszczam. Zwraca pierwszy obiekt w wyniku zapytania i nie przejmuje się, jeśli znaleziono wiele wyników. Jeśli chcesz sprawdzić wiele zwróconych obiektów, użyj.get()
zamiast tego..get()
nie nadaje się do jego potrzeb. Prawidłową odpowiedź na to pytanie można znaleźć poniżej przez @kaapstorm i jest to zdecydowanie bardziej odpowiednia odpowiedź. Nadużywanie wfilter()
ten sposób może prowadzić do nieoczekiwanych konsekwencji, z czego OP prawdopodobnie nie zdawał sobie sprawy (chyba że czegoś tu brakuje)MultipleObjectsReturned()
. Jeśli zwracany wynik nie powinien zwrócić wielu obiektów, nie powinien być traktowany jako taki. Nastąpiła długa debata na ten temat tutajMożna to zrobić na dwa sposoby;
Lub możesz użyć opakowania:
Nazwij to tak
źródło
queryset
metody na zrobienie tego przed 1.6! Ale jak na ten konstrukt - jest po prostu niezdarny. To nie jest „zło”, ponieważ tak powiedział jakiś autor tutoriala w Twoim ulubionym języku. Spróbuj google: „poproś o wybaczenie zamiast o pozwolenie”.get
Metoda nie powinna zwracaćNone
, więc wyjątek ma sens. Powinieneś używać go w przypadkach, gdy jesteś pewien, że obiekt tam będzie / obiekt ma się tam znajdować. Również używanie takich wyjątków jest uważane za „w porządku”, ponieważ ma to sens. Chcesz miećget
inny kontrakt, więc wychwytujesz wyjątek i pomijasz go, czyli zmianę, której szukasz.Aby dodać przykładowy kod do odpowiedzi sorki (dodałbym to jako komentarz, ale to jest mój pierwszy post i nie mam wystarczającej reputacji, aby dodawać komentarze), zaimplementowałem niestandardowego menedżera get_or_none w następujący sposób:
A teraz mogę to zrobić:
źródło
Możesz także spróbować użyć django irytującego (ma inne przydatne funkcje!)
zainstaluj za pomocą:
źródło
Daj Foo jego niestandardowego menedżera . To całkiem proste - po prostu umieść kod w funkcji w menedżerze niestandardowym, ustaw menedżera niestandardowego w modelu i wywołaj go za pomocą
Foo.objects.your_new_func(...)
.Jeśli potrzebujesz funkcji ogólnej (aby używać jej w dowolnym modelu, nie tylko z niestandardowym menedżerem), napisz własną i umieść ją w dowolnym miejscu na ścieżce Pythona i zaimportuj, nie brudząc się już.
źródło
Niezależnie od tego, czy robisz to za pośrednictwem menedżera, czy funkcji ogólnej, możesz również chcieć złapać `` MultipleObjectsReturned '' w instrukcji TRY, ponieważ funkcja get () podniesie to, jeśli twoje kwargs pobiorą więcej niż jeden obiekt.
Opierając się na funkcji ogólnej:
aw menedżerze:
źródło
Oto odmiana funkcji pomocniczej, która pozwala opcjonalnie przekazać
QuerySet
instancję, na wypadek gdybyś chciał pobrać unikalny obiekt (jeśli jest obecny) z zestawu zapytań innego niżall
zestaw zapytań obiektów modelu (np. Z podzbioru elementów potomnych należących do instancja nadrzędna):Można to wykorzystać na dwa sposoby, np .:
obj = get_unique_or_none(Model, *args, **kwargs)
jak omówiono wcześniejobj = get_unique_or_none(Model, parent.children, *args, **kwargs)
źródło
Myślę, że w większości przypadków możesz po prostu użyć:
Tylko jeśli nie jest krytyczne, że nowy wpis zostanie dodany w tabeli Foo (inne kolumny będą miały wartości Brak / domyślne)
źródło