Django: получить объект из БД или None, если ничего не найдено - PullRequest
95 голосов
/ 03 октября 2009

Есть ли какая-либо функция Django, которая позволит мне получить объект из базы данных, или None, если ничего не совпадает?

Сейчас я использую что-то вроде:

foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None

Но это не очень понятно, и везде грязно.

Ответы [ 8 ]

137 голосов
/ 03 октября 2009

Есть два способа сделать это;

try:
    foo = Foo.objects.get(bar=baz)
except model.DoesNotExist:
    foo = None

Или вы можете использовать обертку:

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

Назови это так

foo = get_or_none(Foo, baz=bar)
85 голосов
/ 30 июля 2013

В Django 1.6 вы можете использовать first() метод Queryset. Возвращает первый объект, соответствующий набору запросов, или None, если нет соответствующего объекта.

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

p = Article.objects.order_by('title', 'pub_date').first()
82 голосов
/ 07 января 2010

Чтобы добавить пример кода в ответ Сорки (я бы добавил это как комментарий, но это мой первый пост, и у меня недостаточно репутации, чтобы оставлять комментарии), я реализовал собственный менеджер get_or_none, например, так:

from django.db import models

class GetOrNoneManager(models.Manager):
    """Adds get_or_none method to objects
    """
    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except self.model.DoesNotExist:
            return None

class Person(models.Model):
    name = models.CharField(max_length=255)
    objects = GetOrNoneManager()

И теперь я могу сделать это:

bob_or_none = Person.objects.get_or_none(name='Bob')
13 голосов
/ 08 мая 2014

Вы также можете попробовать использовать раздражающий django (у него есть другие полезные функции!)

установить его с:

pip install django-annoying

from annoying.functions import get_object_or_None
get_object_or_None(Foo, bar=baz)
9 голосов
/ 03 октября 2009

Дайте Foo его собственный менеджер . Это довольно просто - просто поместите свой код в функцию в пользовательском менеджере, установите пользовательский менеджер в вашей модели и вызовите его с помощью Foo.objects.your_new_func(...).

Если вам нужна универсальная функция (чтобы использовать ее на любой модели, а не только с пользовательским менеджером), напишите свою собственную и поместите ее где-нибудь на пути к Python и импортируйте, не беспорядочно.

4 голосов
/ 29 ноября 2012

Независимо от того, выполняете ли вы это с помощью менеджера или универсальной функции, вы также можете захотеть перехватить 'MultipleObjectsReturned' в операторе TRY, поскольку функция get () будет вызывать это, если ваши kwargs получат более одного объекта.

Опираясь на обобщенную функцию:

def get_unique_or_none(model, *args, **kwargs):
    try:
        return model.objects.get(*args, **kwargs)
    except (model.DoesNotExist, model.MultipleObjectsReturned), err:
        return None

и в менеджере:

class GetUniqueOrNoneManager(models.Manager):
    """Adds get_unique_or_none method to objects
    """
    def get_unique_or_none(self, *args, **kwargs):
        try:
            return self.get(*args, **kwargs)
        except (self.model.DoesNotExist, self.model.MultipleObjectsReturned), err:
            return None
0 голосов
/ 16 марта 2017

Я думаю, что в большинстве случаев вы можете просто использовать:

foo, created = Foo.objects.get_or_create(bar=baz)

Только если не критично, что новая запись будет добавлена ​​в таблицу Foo (другие столбцы будут иметь значения None / default)

0 голосов
/ 30 июля 2014

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

def get_unique_or_none(model, queryset=None, *args, **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(*args, **kwargs)
    except model.DoesNotExist:
        return None

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

  1. obj = get_unique_or_none(Model, *args, **kwargs) как обсуждалось ранее
  2. obj = get_unique_or_none(Model, parent.children, *args, **kwargs)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...