Как получить объект, если он существует, или Нет, если он не существует?

Когда я попрошу диспетчера модели получить объект, он поднимает DoesNotExist, когда нет соответствующего объекта.

go = Content.objects.get(name="baby")

Вместо DoesNotExist, как я могу вместо go быть None?

Ответ 1

Существует не "встроенный" способ сделать это. Каждый раз Django будет поднимать исключение DoNotExist. Идиоматический способ справиться с этим в python состоит в том, чтобы обернуть его в try catch:

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

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

Ответ 2

Начиная с django 1.6, вы можете использовать метод first() следующим образом:

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

Ответ 3

Из 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

Ответ 4

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

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

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

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

go будет None, если никакая запись не соответствует else, будет возвращена запись Content.

Примечание. Это приведет к возникновению исключения. MultipleObjectsReturned, если для name= "baby" выбрано более одной записи

Ответ 5

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

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()

Ответ 7

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

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

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

Ответ 8

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

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

а затем включить его в контентный класс Model

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

Таким образом, это легко можно рассматривать в представлениях i.e.

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

Ответ 9

Это одна из тех раздражающих функций, которые вы, возможно, не захотите повторно реализовать:

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

Ответ 10

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

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

Ответ 11

Я думаю, что неплохо использовать 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.

Ответ 12

Здесь приведена вариация вспомогательной функции, которая позволяет вам в случае необходимости передать экземпляр 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` 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

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

  • obj = get_unique_or_none(Model, **kwargs), как обсуждалось ранее
  • obj = get_unique_or_none(Model, parent.children, **kwargs)

Ответ 13

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

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. С одной стороны, "легче просить прощения, чем разрешения". Хотя я согласен с этим, я считаю, что исключение должно остаться, ну, исключение, а "идеальный случай" должен работать без удара.

Ответ 14

Начиная с django 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()

Ответ 15

Мы можем использовать исключение Django builtin, которое привязано к моделям с именем .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