Який правильний спосіб перевірити, якщо об’єкт існує у поданні django без повернення 404?


91

Мені потрібно перевірити, чи існує об’єкт, і повернути об’єкт, а потім на основі цього виконати дії. Який правильний спосіб це зробити, не повернувши 404?

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

if listing:

Расіель, чи можу я запропонувати вам прийняти іншу відповідь? Здається, це правильний спосіб зробити це, і він був підтриманий набагато більше, ніж прийнята відповідь.
Azendale

1
Я можу це розглянути, однак існує, було введено в Django 1.2, який був випущений 17 травня 2010 р. Якщо ви помітили, що моє запитання було надіслано в 09 ... це була правильна відповідь на той час. Якщо зараз Exists () вважається найкращим способом зробити це, я думаю, було б семантично правильно вибрати другу відповідь, правда?
Расіель

Расіель, логічно, що тоді це була правильна відповідь. Але сайти stackoverflow, схоже, стосуються не лише створення набору хороших / офіційних питань з найкращими відповідями, скільки сайтів, які шукають рішення проблем людей. Звідси моя пропозиція вибрати те, що зараз є "офіційно правильною" відповіддю.
Azendale

if listing:Повинно бути else:.
Хроніал,

Відповіді:


116

Я б не використовував обгортку 404, якщо вам не дадуть 404. Це неправильне використання намірів. Просто впіймайте DoesNotExist.

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

+1: Так, це краще рішення, ніж прийняте, якщо ви не хочете 404.
Карл Мейер,

я, це, мабуть, найкраще рішення
Расіель

3
Це рішення працює краще, ніж exists()якщо вам потрібно щось зробити з об’єктом.
SaeX

2
Мені подобається додавати values_list('id', flat=True). якщо мені потрібно просто подивитися, чи існуєlisting = RealEstateListing.objects.values_list('id', flat=True).get(slug_url=slug)
erajuan

У цьому синтаксисі мені здається дивним те, що RealEstateListing.DoesNotExistце стосується моделі, а не самого об’єкта. Чому це не так RealEstateListing.objects.get(slug_url=slug).DoesNotExist?
Максим Валле

198

Ви також можете зробити:

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

Іноді стає зрозумілішим використання try: except:блоку, а інколи однолінійний exists()код робить код чіткішим ... все залежить від вашої логіки програми.



7
це кращий спосіб, і на нього повинна бути відповідь
Jharwood

3
Я припускаю, що exists()це не працює get(), так?
Едуард Лука,

8
Зауважте, що це рішення є дійсним лише у тому випадку, якщо ви не збираєтесь використовувати відповідний об’єкт. В іншому випадку (як у ситуації з операційними системами) це неправильно і набагато повільніше, ніж прийняте рішення: якщо ви зробите get()пізніше, воно надішле другий запит до бази даних.
Хроніал,

1
Якщо ви перевіряєте існування, щоб щось робити з об'єктом (якщо він існує), тоді я віддаю перевагу try-exceptнад exists().
Jithin Pavithran

7
listing = RealEstateListing.objects.filter(slug_url=slug).first() 

2
Це найкраще рішення, якщо пізніше потрібно використати потенційний об’єкт, оскільки для цього потрібно лише одне призначення, а також уникнути необхідності використовувати блок спроби / крім. Зверніть увагу, що ви можете перевірити існування пізніше просто за допомогоюif listing:
Майкла Хейса,

Уникати спроб / крім поганої практики. Одним з найважливіших аспектів розробки програмного забезпечення є можливість контролювати винятки, щоб забезпечити хороший досвід роботи з користувачем. Повідомте людей, коли щось не працює належним чином. Другий; якщо ви хочете перевірити наявність QuerySet, використовуйте .exists (), інакше є об'єктом. Перевірте наявність на основі їх первинного ключа .... if object.pk: // запустити код () Цей запит набагато швидший, ніж отримання всіх даних об’єкта. Ви просто хочете знати, чи існує.
Вольфганг Леон

2
Вже було рішення за допомогою try / Osim та .exists(). Я думаю, це гарна ідея в SO, щоб мати кілька різних відповідей, як це робити. Можливо, це краще для тих, хто також хоче використовувати об'єкт, якщо він існує. Я б не встановлював жодних правил, якщо спроб / крім цього слід уникати чи ні. Іноді це добре, а іноді і погано, наприклад, якщо ви просто хочете зробити дуже компактний код.
Генрік Хейно,

0

Я б зробив це так просто:

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

Я не бачу потреби в спробі / лові. Якщо в результаті потенційно кілька об'єктів, використовуйте first (), як показав користувач Henrik Heino


Якщо ви не зробите .first () для набору запитів або .first () в умовному, це завжди поверне True.
Б.Адлер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.