Jaki jest właściwy sposób sprawdzenia, czy obiekt istnieje w widoku django bez zwracania błędu 404?

93

Muszę sprawdzić, czy obiekt istnieje i zwrócić obiekt, a następnie na podstawie tego wykonać akcje. Jaki jest właściwy sposób, aby to zrobić bez zwracania kodu 404?

try:
    listing = RealEstateListing.objects.get(slug_url = slug)
except:
    listing = None

if listing:
Rasiel
źródło
Rasiel, czy mogę zasugerować rozważenie przyjęcia innej odpowiedzi? Wydaje się, że jest to właściwy sposób zrobienia tego i spotkało się z dużo większym uznaniem niż zaakceptowana odpowiedź.
Azendale
1
Mogę to uznać, jednak istnieje zostało wprowadzone w Django 1.2, które zostało wydane 17 maja 2010 r. Jeśli zauważysz, że moje pytanie zostało przesłane w 09… to była wtedy poprawna odpowiedź. Jeśli Exists () jest teraz uważane za najlepszy sposób na zrobienie tego, myślę, że byłoby semantycznie poprawne wybranie drugiej odpowiedzi, prawda?
Rasiel
Rasiel, to ma sens, że to była wtedy poprawna odpowiedź. Ale strony stackoverflow wydają się w równym stopniu polegać na tworzeniu zestawu dobrych / oficjalnych pytań z najlepszymi odpowiedziami, jak na znajdowaniu rozwiązań problemów ludzi. Stąd moja sugestia, aby wybrać odpowiedź, która jest obecnie „oficjalnie poprawna”.
Azendale,
if listing:Powinno być else:.
Chronial

Odpowiedzi:

117

Nie użyłbym opakowania 404, gdybyś nie otrzymał 404. To jest nadużycie intencji. Zamiast tego po prostu złap DoesNotExist.

try:
    listing = RealEstateListing.objects.get(slug_url=slug)
except RealEstateListing.DoesNotExist:
    listing = None
ironfroggy
źródło
+1: Tak, jest to lepsze rozwiązanie niż przyjęte, jeśli nie chcesz 404.
Carl Meyer
tak, to wydaje się być lepszym rozwiązaniem
Rasiel
3
To rozwiązanie działa lepiej niż exists()gdybyś musiał coś zrobić z obiektem.
SaeX
2
Lubię dodawać values_list('id', flat=True). jeśli muszę tylko sprawdzić, czy istniejelisting = RealEstateListing.objects.values_list('id', flat=True).get(slug_url=slug)
erajuan
To, co wydaje mi się dziwne w tej składni, RealEstateListing.DoesNotExistto odwoływanie się do modelu, a nie do samego obiektu. Dlaczego tak nie jest RealEstateListing.objects.get(slug_url=slug).DoesNotExist?
Maxim Vallee
200

Możesz też:

if not RealEstateListing.objects.filter(slug_url=slug).exists():
    # do stuff...

Czasami bardziej oczywiste jest użycie try: except:bloku, a innym razem jednolinijka exists()sprawia, że ​​kod wygląda jaśniej ... wszystko zależy od logiki aplikacji.

zzart
źródło
7
to jest lepszy sposób i powinien mieć odpowiedź
Jharwood
3
Zakładam, że exists()to nie działa get(), prawda?
Eduard Luca,
9
Zwróć uwagę, że to rozwiązanie jest ważne tylko wtedy, gdy nie zamierzasz używać danego obiektu. W przeciwnym razie (jak w przypadku OP) jest źle i dużo wolniej niż przyjęte rozwiązanie: jeśli zrobisz to get()później, wyśle ​​drugie zapytanie do bazy danych.
Chronial
1
Jeśli sprawdzanie istnienia zrobić coś z obiektu (jeśli istnieje), wtedy wolę try-exceptponad exists().
Jithin Pavithran
7
listing = RealEstateListing.objects.filter(slug_url=slug).first() 
Henrik Heino
źródło
2
Jest to najlepsze rozwiązanie, jeśli musisz później użyć potencjalnego obiektu, ponieważ wymaga on tylko jednego przypisania i pozwala uniknąć używania bloku try / except. Zauważ, że możesz później przetestować istnienie po prostuif listing:
Michael Hays,
Unikanie prób / z wyjątkiem jest złą praktyką. Jednym z najważniejszych aspektów rozwoju oprogramowania jest możliwość kontrolowania wyjątków, aby zapewnić dobre wrażenia użytkownika. Poinformuj innych, gdy coś nie działa prawidłowo. Druga; jeśli chcesz sprawdzić istnienie QuerySet, użyj .exists (), w przeciwnym razie jest obiektem. Sprawdź, czy istnieje klucz podstawowy ... if object.pk: // run code () To zapytanie jest znacznie szybsze niż pobieranie wszystkich danych obiektu. Chcesz tylko wiedzieć, czy istnieje.
Wolfgang Leon,
2
Było już rozwiązanie wykorzystujące try / except i .exists(). Myślę, że dobrym pomysłem w SO jest posiadanie wielu różnych odpowiedzi, jak robić różne rzeczy. Może to jest lepsze dla tych, którzy również chcą użyć obiektu, jeśli istnieje. Nie ustalałbym żadnych zasad, jeśli należy unikać prób / wyjątków, czy nie. Czasami jest to dobre, a czasami złe, na przykład, jeśli chcesz stworzyć bardzo kompaktowy kod.
Henrik Heino,
0

Zrobiłbym to w następujący sposób:

listing = RealEstateListing.objects.filter(slug_url=slug)
if listing:
    # do stuff

Nie widzę potrzeby próbowania / łapania. Jeśli w wyniku jest potencjalnie kilka obiektów, użyj metody first (), jak pokazuje użytkownik Henrik Heino

Greg Holst
źródło
O ile nie wykonasz .first () na zestawie zapytań lub .first () w warunku, zawsze zwróci to True.
B.Adler