2010-06-22 3 views

ответ

168

Для этого не существует «встроенного» способа. Каждый раз Django будет поднимать исключение DoNotExist. идиоматических способ справиться с этим в питона, чтобы обернуть его в попытке поймать:

try: 
    go = SomeModel.objects.get(foo='bar') 
except SomeModel.DoesNotExist: 
    go = None 

То, что я делаю, это подкласс models.Manager, создать safe_get как код выше и использовать этот менеджер для моего моделей. Таким образом, вы можете написать: SomeModel.objects.safe_get(foo='bar').

+5

+1 для обнаружения конкретного исключения. –

+6

Приятное использование SomeModel.DoesNotExist вместо импорта исключения. – Symmitchry

+102

Это решение длиной четыре строки. Для меня это слишком много. С django 1.6 вы можете использовать 'SomeModel.objects.filter (foo = 'bar'). First()' this возвращает первое совпадение или None. Это не сработает, если существует несколько экземпляров типа 'queryset.get()' – guettli

23

From django docs

get() поднимает DoesNotExist исключение, если объект не обнаружен при заданных параметрах. Это исключение также является атрибутом класса модели. DoesNotExist исключение наследует от django.core.exceptions.ObjectDoesNotExist

Вы можете поймать исключение и назначить None идти.

from django.core.exceptions import ObjectDoesNotExist 
try: 
    go = Content.objects.get(name="baby") 
except ObjectDoesNotExist: 
    go = None 
17

Для этого можно создать общую функцию.

def get_or_none(classmodel, **kwargs): 
    try: 
     return classmodel.objects.get(**kwargs) 
    except classmodel.DoesNotExist: 
     return None 

Используйте это, как показано ниже:

go = get_or_none(Content,name="baby") 

идти не будет None, если запись не соответствует еще будет возвращать содержимое записи.

Примечание: Это вызывает исключение MultipleObjectsReturned, если более чем один элемент возвращается на имя = «ребенок»

6

Обработка исключений в разных точках вашего мнения может быть действительно cumbersome..What об определении пользовательских Model Manager, в models.py файл, как

class ContentManager(model.Manager): 
    def get_nicely(self, **kwargs): 
     try: 
      return self.get(kwargs) 
     except(KeyError, Content.DoesNotExist): 
      return None 

, а затем включить его в классе содержание модели

class Content(model.Model): 
    ... 
    objects = ContentManager() 

Таким образом, он может быть EAS ILY торговал мнения, т.е.

post = Content.objects.get_nicely(pk = 1) 
if post: 
    # Do something 
else: 
    # This post doesn't exist 
+0

Мне очень нравится это решение, но он не смог заставить его работать как и при использовании python 3.6. Хотелось оставить заметку о том, что изменение возврата в ContentManager для 'return self.get (** kwargs)' заставил его работать для меня. Не сказать ничего плохого в ответе, просто совет для тех, кто пытается использовать его с более поздними версиями (или с тем, что еще не помогло мне работать для меня). – skagzilla

9

Чтобы сделать вещи проще, вот фрагмент кода, который я написал, основываясь на данных из замечательных ответов здесь:

class MyManager(models.Manager): 

    def get_or_none(self, **kwargs): 
     try: 
      return self.get(**kwargs) 
     except ObjectDoesNotExist: 
      return None 

И тогда в вашей модели:

class MyModel(models.Model): 
    objects = MyManager() 

Всё. Теперь у вас есть MyModel.objects.get(), а также MyModel.objetcs.get_or_none()

+4

также, не забудьте импортировать: из django.core.exceptions import ObjectDoesNotExist –

8

вы могли бы использовать exists с фильтром:

Content.objects.filter(name="baby").exists() 
#returns False or True depending on if there is anything in the QS 

просто альтернатива, если вы хотите знать, если он существует

+1

Это вызовет дополнительный вызов базы данных, если существует. Неплохая идея – Christoffer

1

Вот вариации на вспомогательную функцию, которая позволяет вам необязательно передать экземпляр QuerySet, если вы хотите получить уникальный объект (если он есть) из набора запросов, отличного от заданного запроса модели all (например, из подмножества дочерних элементов, принадлежащих родительскому экземпляру):

def get_unique_or_none(model, queryset=None, **kwargs): 
    """ 
     Performs the query on the specified `queryset` 
     (defaulting to the `all` queryset of the `model`'s default manager) 
     and returns the unique object matching the given 
     keyword arguments. Returns `None` if no match is found. 
     Throws a `model.MultipleObjectsReturned` exception 
     if more than one match is found. 
    """ 
    if queryset is None: 
     queryset = model.objects.all() 
    try: 
     return queryset.get(**kwargs) 
    except model.DoesNotExist: 
     return None 

Это можно использовать двумя способами, например:

  1. obj = get_unique_or_none(Model, **kwargs), как previosuly обсудили
  2. obj = get_unique_or_none(Model, parent.children, **kwargs)
+0

Я вижу, что 'django annoying' уже обрабатывает этот случай. – Gary

76

С Джанго 1.6 вы можете использовать first() метод следующим образом:

Content.objects.filter(name="baby").first() 
+10

В этом случае ошибка не возникает, если имеется более одного совпадения. –

+1

Мне нравится это решение, потому что, используя 'objecst.get()' infers, мы знаем, что в базе данных есть либо одно, либо нет. – EmptyFlash

+2

«FeroxTL» вам нужно кредитовать @guettli за этот ответ, так как он прокомментировал это на принятом ответе за год до вашего поста. – colminator

1

Без исключения:

if SomeModel.objects.filter(foo='bar').exists(): 
    x = SomeModel.objects.get(foo='bar') 
else: 
    x = None 

Использование исключение:

try: 
    x = SomeModel.objects.get(foo='bar') 
except SomeModel.DoesNotExist: 
    x = None 

Существует немного аргумента о том, когда следует использовать исключение в Python. С одной стороны, «легче просить прощения, чем разрешения». Хотя я согласен с этим, я считаю, что исключение должно остаться, ну, исключение, а «идеальный случай» должен работать без удара.

1

С Джанго 1.7 года вы можете сделать так:

class MyQuerySet(models.QuerySet): 

    def get_or_none(self, **kwargs): 
     try: 
      return self.get(**kwargs) 
     except self.model.DoesNotExist: 
      return None 


class MyBaseModel(models.Model): 

    objects = MyQuerySet.as_manager() 


class MyModel(MyBaseModel): 
    ... 

class AnotherMyModel(MyBaseModel): 
    ... 

Преимущество "MyQuerySet.as_manager()" является то, что оба из следующих будет работать:

MyModel.objects.filter(...).get_or_none() 
MyModel.objects.get_or_none() 
7

Это один из тех, annoying functions, что вы не можете повторно реализовать:

from annoying.functions import get_object_or_None 
#... 
user = get_object_or_None(Content, name="baby") 
1

Мы можем использовать Django встроенного исключение которых ttached для моделей с именем .DoesNotExist. Таким образом, нам не нужно импортировать исключение ObjectDoesNotExist.

Вместо делать:

from django.core.exceptions import ObjectDoesNotExist 

try: 
    content = Content.objects.get(name="baby") 
except ObjectDoesNotExist: 
    content = None 

Мы можем сделать это:

try: 
    content = Content.objects.get(name="baby") 
except Content.DoesNotExist: 
    content = None 
2

Если вы хотите простое решение одной линии, которая не предполагает обработку исключений, условные операторы или требование Django 1.6+, сделать это вместо того, чтобы:

x = next(iter(SomeModel.objects.filter(foo='bar')), None) 
1

Я думаю, что это ISN «т плохая идея использовать get_object_or_404()

from django.shortcuts import get_object_or_404 

def my_view(request): 
    my_object = get_object_or_404(MyModel, pk=1) 

Этот пример эквивалентен:

from django.http import Http404 

def my_view(request): 
    try: 
     my_object = MyModel.objects.get(pk=1) 
    except MyModel.DoesNotExist: 
     raise Http404("No MyModel matches the given query.") 

Вы можете узнать больше о get_object_or_404() в онлайн-документации django.

Смежные вопросы