Ответы:
Не существует встроенного способа сделать это. Django будет вызывать исключение DoesNotExist каждый раз. Идиоматический способ справиться с этим в python - это обернуть его в попытку:
try:
go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
go = None
То, что я сделал, это подкласс моделей. Менеджер, создайте safe_get
подобный код выше и используйте этот менеджер для моих моделей. Таким образом , вы можете написать: SomeModel.objects.safe_get(foo='bar')
.
SomeModel.objects.filter(foo='bar').first()
это возвращает первое совпадение или None. Это не подведет, если есть несколько примеров, какqueryset.get()
filter().first()
я думаю, что исключение - это путь.
Начиная с django 1.6, вы можете использовать метод first () следующим образом:
Content.objects.filter(name="baby").first()
get()
вызываетDoesNotExist
исключение, если объект не найден для данных параметров. Это исключение также является атрибутом класса модели. ВDoesNotExist
исключение наследует отdjango.core.exceptions.ObjectDoesNotExist
Вы можете поймать исключение и назначить None
идти.
from django.core.exceptions import ObjectDoesNotExist
try:
go = Content.objects.get(name="baby")
except ObjectDoesNotExist:
go = None
Вы можете создать универсальную функцию для этого.
def get_or_none(classmodel, **kwargs):
try:
return classmodel.objects.get(**kwargs)
except classmodel.DoesNotExist:
return None
Используйте это как ниже:
go = get_or_none(Content,name="baby")
go будет None, если ни одна запись не соответствует, иначе вернет запись Content.
Примечание. Возникает исключение MultipleObjectsReturned, если для name = "baby" возвращено более одной записи.
Вы можете сделать это следующим образом:
go = Content.objects.filter(name="baby").first()
Теперь переменная go может быть либо нужным вам объектом, либо None
Ссылка: https://docs.djangoproject.com/en/1.8/ref/models/querysets/#django.db.models.query.QuerySet.first
Чтобы упростить задачу, вот фрагмент кода, который я написал, на основе входных данных из замечательных ответов здесь:
class MyManager(models.Manager):
def get_or_none(self, **kwargs):
try:
return self.get(**kwargs)
except ObjectDoesNotExist:
return None
И тогда в вашей модели:
class MyModel(models.Model):
objects = MyManager()
Вот и все. Теперь у вас есть MyModel.objects.get (), а также MyModel.objetcs.get_or_none ()
Вы можете использовать exists
с фильтром:
Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QS
просто альтернатива, если вы только хотите знать, существует ли он
Note: If you only want to determine if at least one result exists (and don’t need the actual objects), it’s more efficient to use exists().
exists()
будет использоваться с if
предложением перед извлечением объекта, что приведет к двойному попаданию в БД. Я все еще буду держать комментарий в случае, если он поможет кому-то еще.
Обработка исключений в разных точках в ваших представлениях может быть очень трудоемкой. Как насчет определения собственного менеджера моделей в файле models.py, например
class ContentManager(model.Manager):
def get_nicely(self, **kwargs):
try:
return self.get(kwargs)
except(KeyError, Content.DoesNotExist):
return None
а затем включить его в класс модели содержимого
class Content(model.Model):
...
objects = ContentManager()
Таким образом, это может быть легко решено в представлениях, т.е.
post = Content.objects.get_nicely(pk = 1)
if post:
# Do something
else:
# This post doesn't exist
return self.get(**kwargs)
его работать на меня. Не говорить, что с ответом что-то не так, просто совет для тех, кто пытается использовать его с более поздними версиями (или с тем, что мешало мне работать).
Это одна из тех раздражающих функций, которые вы, возможно, не захотите повторно реализовывать:
from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")
get_object_or_None
но обнаружил, что он все еще вызывает, MultipleObjectsReturned
если более одного объекта. Таким образом, пользователь может рассмотреть окружение с try-except
(которое уже есть в самой функции try-except
).
Я думаю, что это не плохая идея использовать get_object_or_404()
from django.shortcuts import get_object_or_404
def my_view(request):
my_object = get_object_or_404(MyModel, pk=1)
Этот пример эквивалентен:
from django.http import Http404
def my_view(request):
try:
my_object = MyModel.objects.get(pk=1)
except MyModel.DoesNotExist:
raise Http404("No MyModel matches the given query.")
Вы можете прочитать больше о get_object_or_404 () в онлайн документации django.
С django 1.7 вы можете делать следующее:
class MyQuerySet(models.QuerySet):
def get_or_none(self, **kwargs):
try:
return self.get(**kwargs)
except self.model.DoesNotExist:
return None
class MyBaseModel(models.Model):
objects = MyQuerySet.as_manager()
class MyModel(MyBaseModel):
...
class AnotherMyModel(MyBaseModel):
...
Преимущество «MyQuerySet.as_manager ()» заключается в том, что оба следующих варианта будут работать:
MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()
Вот вариант вспомогательной функции, которая позволяет вам при желании передать QuerySet
экземпляр, если вы хотите получить уникальный объект (если имеется) из набора запросов, отличного от набора запросов all
объектов модели (например, из подмножества дочерних элементов, принадлежащих родительский экземпляр):
def get_unique_or_none(model, queryset=None, **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(**kwargs)
except model.DoesNotExist:
return None
Это можно использовать двумя способами, например:
obj = get_unique_or_none(Model, **kwargs)
как и ранее обсуждалосьobj = get_unique_or_none(Model, parent.children, **kwargs)
Без исключений:
if SomeModel.objects.filter(foo='bar').exists():
x = SomeModel.objects.get(foo='bar')
else:
x = None
Используя исключение:
try:
x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
x = None
Существует немного спора о том, когда следует использовать исключение в Python. С одной стороны, «проще просить прощения, чем разрешения». Хотя я согласен с этим, я считаю, что исключение должно оставаться, ну, исключение, и «идеальный случай» должен выполняться, не затрагивая его.
Мы можем использовать встроенное исключение Django, которое прикреплено к моделям, названным как .DoesNotExist
. Таким образом, мы не должны импортировать ObjectDoesNotExist
исключения.
Вместо этого:
from django.core.exceptions import ObjectDoesNotExist
try:
content = Content.objects.get(name="baby")
except ObjectDoesNotExist:
content = None
Мы можем это сделать:
try:
content = Content.objects.get(name="baby")
except Content.DoesNotExist:
content = None
Это подражатель из get_object_or_404 Джанго за исключением того, что метод возвращает None. Это чрезвычайно полезно, когда нам нужно использовать only()
запрос, чтобы получить только определенные поля. Этот метод может принимать модель или набор запросов.
from django.shortcuts import _get_queryset
def get_object_or_none(klass, *args, **kwargs):
"""
Use get() to return an object, or return None if object
does not exist.
klass may be a Model, Manager, or QuerySet object. All other passed
arguments and keyword arguments are used in the get() query.
Like with QuerySet.get(), MultipleObjectsReturned is raised if more than
one object is found.
"""
queryset = _get_queryset(klass)
if not hasattr(queryset, 'get'):
klass__name = klass.__name__ if isinstance(klass, type) else klass.__class__.__name__
raise ValueError(
"First argument to get_object_or_none() must be a Model, Manager, "
"or QuerySet, not '%s'." % klass__name
)
try:
return queryset.get(*args, **kwargs)
except queryset.model.DoesNotExist:
return None
Может быть, лучше вы используете:
User.objects.filter(username=admin_username).exists()