logo

Возврат None вместо 'DoesNotExist' в Django: способы обхода

Быстрый ответ

Если вам необходимо получить некий объект из базы данных Django или получить None в случае, если объект отсутствует, воспользуйтесь следующим подходом:

Python
Скопировать код
instance = MyModel.objects.filter(pk=some_id).first()

В данном примере instance будет или экземпляром класса MyModel (если таковой находится в базе данных), или None (если такого объекта нет).

Мы советуем познакомиться с немного более изощренными подходами к решению данной задачи. Смотрите ниже.

Назад к базовому: Пользовательский менеджер запросов для безопасного получения объекта

Основы метода safe_get

Создание собственного менеджера запросов с использованием метода safe_get позволяет изящно обработать ситуации, когда искомый объект отсутствует в базе данных. Метод safe_get выполняет get-запрос в блоке try...except и возвращает None, тем самым предотвращает возникновение исключения.

Python
Скопировать код
from django.core.exceptions import ObjectDoesNotExist

class SafeGetManager(models.Manager):
    def safe_get(self, **kwargs):
        try:
            return self.get(**kwargs)
        except self.model.DoesNotExist:
            return None

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

Использование метода first()

Метод first(), появившийся в Django начиная с версии 1.6, стал прекрасным инструментом ORM. Он возвращает первый найденный объект либо None, предотвращая тем самым возникновение исключений.

Python
Скопировать код
instance = MyModel.objects.filter(name="value").first()
# Получим экземпляр MyModel или None

За пределами базового: распространенные сценарии

Когда объект пропустил встречу

Если вы не можете найти объект, используйте safe_get или .first(), чтобы получить None вместо того, чтобы перехватичвать исключение DoesNotExist вручную.

Обрабатываем исключения как профи

Если нужно точное контролирование процесса обращения к несуществующему объекту, применяйте блок try-except с SomeModel.DoesNotExist.

Python
Скопировать код
try:
    instance = MyModel.objects.get(pk=some_id)
except MyModel.DoesNotExist:
    instance = None

Экономим ресурсы с помощью метода exists()

Используйте exists() для проверки наличия объекта без загрузки всего его содержимого.

Python
Скопировать код
if MyModel.objects.filter(pk=some_id).exists():
    # Объект найден, можно радоваться
else:
    # К сожалению, объект не найден

Обзор с высоты птичьего полета: Визуализация

Представьте, что вы летите над библиотекой, взирая на ряды книжных полок:

Markdown
Скопировать код
Полки Библиотеки:
- Программирование на Python 📗
- Разработка на Django 📘?    <--- Вы здесь!
- Веб-дизайн 📙

Вы пытаетесь найти нужную книгу:

Python
Скопировать код
book = library.get('Программирование на Python 📗', None)

И, независимо от того, нашли ли вы книгу или нет, продолжаете свой полет:

Markdown
Скопировать код
Результат:
- Найдено: 📘 (Замечательно!)
- Не найдено: None (Не беда...)

Вот так визуализируется работа метода .get() в Django.

Торжественное завершение: широкая обработка исключений

Захватываем все с помощью ObjectDoesNotExist

Чтобы перехватить исключения об отсутствии объектов любых моделей, используйте ObjectDoesNotExist.

Python
Скопировать код
from django.core.exceptions import ObjectDoesNotExist

try:
    instance = MyModel.objects.get(pk=some_id)
except ObjectDoesNotExist:
    instance = None

Использование ObjectDoesNotExist делает ваш код более универсальным.

Оптимизируем код с помощью пользовательских менеджеров и метода .first()

Путем внедрения логики метода get в пользовательский менеджер вы следуете принципу DRY (Don't Repeat Yourself – не повторяйте себя). Использование метода first() также способствует поддержанию чистоты кода и его читаемости.