Evgenii Legotckoi
15 мая 2018 г. 20:07

Django - Snippet 001. get_object_or_none

Содержание

В шорткатах Django есть функция get_object_or_404 , но при этом нет функции get_object_or_none , которая может быть полезна в том случае, когда мы не хотим вызывать сразу ошибку 404, но при этом нам необходимо выполнить какие либо действия в том случае, если объект не существует в базе данных.

Удалось найти обсуждение в интернете, где разработчики отписались, что подобный функционал может быть легко внедрён в качесте until функции в рамках проекта разработчика и внедрять его в основной код не требуется.


Подобный функционал мне понадобился для поиска тегов на сайте.

Поэтому я его добавил в ядро сайта в качестве шортката.

shortcuts.py

# -*- coding: utf-8 -*-


def get_object_or_none(klass, *args, **kwargs):
    try:
        return klass._default_manager.get(*args, **kwargs)
    except klass.DoesNotExist:
        return None

Пример

def get_queryset(self, **kwargs):
    q = self.request.GET.get('q')
    tag = get_object_or_none(Tag, name=q)
    if tag:
        return TaggedItem.objects.all().filter(tag=tag)
    return []

Вам это нравится? Поделитесь в социальных сетях!

ПК
  • 19 мая 2018 г. 17:11
Тоже искал подобную функцию, чтобы не обрабатывать каждый раз исключения. И нашёл на so совет использовать вместо неё метод менеджера first(), который возвращает None при пустом queryset. Т.е можно было так
tag = Tag.objects.first()
if tag:
  return tag
return []
Evgenii Legotckoi
  • 19 мая 2018 г. 18:25

В вашем случае происходит подмена сущностей. Вместо того, чтобы взять один конкретный объект, вы забираете queryset а потом берёте из него первый объект. Нехорошо будет, если queryset в каком-то случае вернёт два объекта или более. Проблема в том, что вы не узнаете об этой ошибке никак, а это нарушит логику работы приложения с последствиями в будущем. Мой вариант решения хотя бы порушит приложение и даст знать что существует два одинаковых по каким-то параметрам объекта, и нужно будет принимать меры для исправления.

Лично мне не нравится ваше решение.
ПК
  • 19 мая 2018 г. 18:34

Согласен с тем что ваше решение более очевидно при чтении кода. first() же здесь применяется не совсем по назначению. А с последствиями "моего" решения не согласен. Метод вернёт только один объект, если он существует, или None. А целостность базы данных лучше, наверно, проверять на этапе добавления записи, а не при доступе к ней. В остальном поведение идентично вашему методу.

Evgenii Legotckoi
  • 19 мая 2018 г. 18:44

А вы гарантируете, что метод first вернёт нужный объект, если в таблице две похожих записи? Этого никто не гарантирует. Может возникнуть неопределённое поведение приложения, если запись не так, что требовалась. А насчёт целостности базы данных перед добавлением я согласен, хотя по идее уровни блокировки на чтение записи в самой базе данных должны разруливать такую ситуацию, но у меня случалась подобная ситуация. Увы..

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь