Evgenii Legotckoi
15 травня 2018 р. 20:07

Django – фрагмент 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 вернёт нужный объект, если в таблице две похожих записи? Этого никто не гарантирует. Может возникнуть неопределённое поведение приложения, если запись не так, что требовалась. А насчёт целостности базы данных перед добавлением я согласен, хотя по идее уровни блокировки на чтение записи в самой базе данных должны разруливать такую ситуацию, но у меня случалась подобная ситуация. Увы..

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up