Есть ли функция Django, которая позволит мне получить объект из базы данных, или None, если ничего не подходит?
Сейчас я использую что-то вроде:
foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None
Но это не очень понятно, и иметь везде грязно.
len(foo)
это плохо : " Примечание. Не используйте len () в QuerySets, если все, что вам нужно, - это определить количество записей в наборе. Гораздо эффективнее обрабатывать счет на уровне базы данных, используя SQL SELECT COUNT. (), и Django предоставляет метод count () именно по этой причине. ". Переписано:foo = foo[0] if foo.exists() else None
first()
: PОтветы:
В Django 1.6 вы можете использовать
first()
метод Queryset. Он возвращает первый объект, соответствующий набору запросов, или None, если подходящего объекта нет.Использование:
источник
MultipleObjectsReturned()
возникает, как описано здесь . Вы можете найти лучшие ответы здесьfirst()
работе точно так , как предполагает , чтобы. Он возвращает первый объект в результате запроса и не заботится о том, найдено ли несколько результатов. Если вам нужно проверить наличие нескольких возвращенных объектов, вы должны использовать.get()
вместо этого..get()
не подходит для его нужд. Правильный ответ на этот вопрос можно найти ниже, используя @kaapstorm, и он явно является более подходящим ответом. Злоупотреблениеfilter()
этим способом может привести к неожиданным последствиям, чего OP, вероятно, не осознавал (если я что-то здесь неMultipleObjectsReturned()
. Если не ожидается, что возвращаемый результат вернет несколько объектов, его не следует рассматривать как таковой. Был долго дебаты об этом здесьЕсть два способа сделать это;
Или вы можете использовать обертку:
Назовите это так
источник
queryset
метода для этого до 1.6! Но что касается этой конструкции - она просто корявая. Это не «зло», потому что так сказал автор туториала на вашем любимом языке. Попробуйте погуглить: «просите прощения, а не разрешения».get
Метод не должен возвращатьсяNone
, поэтому исключение имеет смысл. Вы должны использовать его в тех случаях, когда вы уверены, что объект будет там / объект «предполагается» там. Также использование подобных исключений считается «хорошо», потому что в этом есть смысл. Вам нуженget
другой контракт, поэтому вы перехватываете исключение и подавляете его, что и является изменением, которое вам нужно.Чтобы добавить пример кода к ответу Сорки (я бы добавил это как комментарий, но это мой первый пост, и у меня недостаточно репутации, чтобы оставлять комментарии), я реализовал настраиваемый менеджер get_or_none следующим образом:
И теперь я могу это сделать:
источник
Также можно попробовать использовать раздражающий django (у него есть и другие полезные функции!)
установите его с помощью:
источник
Дайте Foo его собственный менеджер . Это довольно просто - просто введите свой код в функцию в пользовательском диспетчере, установите пользовательский диспетчер в своей модели и вызовите его с помощью
Foo.objects.your_new_func(...)
.Если вам нужна универсальная функция (чтобы использовать ее в любой модели, а не только с настраиваемым менеджером), напишите свою собственную и поместите ее где-нибудь на своем пути python и импортируйте, не беспорядочно.
источник
Независимо от того, выполняете ли вы это через менеджер или общую функцию, вы также можете захотеть поймать MultipleObjectsReturned в операторе TRY, поскольку функция get () поднимет это, если ваши kwargs извлекут более одного объекта.
Основываясь на общей функции:
и в диспетчере:
источник
Вот вариант вспомогательной функции, которая позволяет при желании передать
QuerySet
экземпляр, если вы хотите получить уникальный объект (если он есть) из набора запросов, отличного от набора запросовall
объектов модели (например, из подмножества дочерних элементов, принадлежащих к родительский экземпляр):Это можно использовать двумя способами, например:
obj = get_unique_or_none(Model, *args, **kwargs)
как обсуждалось ранееobj = get_unique_or_none(Model, parent.children, *args, **kwargs)
источник
Я думаю, что в большинстве случаев вы можете просто использовать:
Только если не критично, что новая запись будет добавлена в таблицу Foo (другие столбцы будут иметь значения None / по умолчанию)
источник