我如何获得对象,如果它存在,或None,如果它不存在的Django?

当我要求模型管理器获取一个对象时,当没有匹配的对象时,它会引发DoesNotExist

go = Content.objects.get(name="baby")

而不是DoesNotExist,我怎么能让goNone ?

312456 次浏览
没有“内置”的方法来做到这一点。Django每次都会抛出DoesNotExist异常。 在python中处理这个问题的惯用方法是将其包装在try catch中:

try:
go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
go = None

我所做的就是将模型子类化。管理器,创建一个safe_get像上面的代码和使用我的模型的管理器。这样你就可以写:SomeModel.objects.safe_get(foo='bar')

From django docs

如果没有为给定的参数找到对象,get()将引发DoesNotExist异常。这个异常也是模型类的一个属性。DoesNotExist异常继承自django.core.exceptions.ObjectDoesNotExist

你可以捕获异常并将None赋值给go。

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条目。

注意:如果name="baby"返回多个条目,将引发异常MultipleObjectsReturned

你应该在数据模型上处理它以避免这种错误,但你可能更喜欢在运行时像这样记录它:

def get_or_none(classmodel, **kwargs):
try:
return classmodel.objects.get(**kwargs)
except classmodel.MultipleObjectsReturned as e:
print('ERR====>', e)


except classmodel.DoesNotExist:
return None

在视图的不同位置处理异常可能真的很麻烦..在models.py文件中定义一个自定义模型管理器怎么样

class ContentManager(model.Manager):
def get_nicely(self, **kwargs):
try:
return self.get(kwargs)
except(KeyError, Content.DoesNotExist):
return None

然后将其包含在内容Model类中

class Content(model.Model):
...
objects = ContentManager()

通过这种方式,它可以很容易地在视图中处理。

post = Content.objects.get_nicely(pk = 1)
if post:
# Do something
else:
# This post doesn't exist

为了让事情更简单,下面是我根据这里精彩回复的输入编写的代码片段:

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()
< p >就是这样。 现在你有了MyModel.objects.get()和mymodel .objects. get_or_none()

你可以使用带有过滤器的exists:

Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QS

如果你只想知道它是否存在,这是另一种选择

下面是helper函数的一个变体,它允许你有选择地传入一个QuerySet实例,以防你想从模型的all对象的queryset之外的查询集获得唯一对象(如果存在)(例如,从属于父实例的子项的子集):

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

这可以用在两种情况下,例如:

  1. obj = get_unique_or_none(Model, **kwargs),如前所述
  2. obj = get_unique_or_none(Model, parent.children, **kwargs)

从django 1.6开始,你可以像这样使用第()方法:

Content.objects.filter(name="baby").first()

没有例外:

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 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()

它是那些你可能不想重新实现的烦人的功能之一:

from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")

我们可以使用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

你可以这样做:

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

如果你想要一个简单的单行解决方案,不涉及异常处理、条件语句或Django 1.6+的要求,可以这样做:

x = next(iter(SomeModel.objects.filter(foo='bar')), None)

我认为使用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.")

你可以在django在线文档中阅读更多关于get_object_or_404()的内容。

这是Django 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

Maybe更好用:

User.objects.filter(username=admin_username).exists()

我也面临着同样的问题。当你想从你的模型中获取一个元素时,就像@Arthur Debert的回答一样,每次都很难写和读try-except。因此,我的解决方案是创建一个由模型继承的Getter类:

class Getter:
@classmethod
def try_to_get(cls, *args, **kwargs):
try:
return cls.objects.get(**kwargs)
except Exception as e:
return None


class MyActualModel(models.Model, Getter):
pk_id = models.AutoField(primary_key=True)
...

通过这种方式,我可以得到MyActualModelNone的实际元素:

MyActualModel.try_to_get(pk_id=1)

我使用的是Django 2.2.16。这就是我解决这个问题的方法:

from typing import Any


from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.base import ModelBase
from django.db.models.manager import Manager




class SManager(Manager):
def get_if_exist(self, *args: Any, **kwargs: Any):
try:
return self.get(*args, **kwargs)
except ObjectDoesNotExist:
return None




class SModelBase(ModelBase):
def _prepare(cls):
manager = SManager()
manager.auto_created = True
cls.add_to_class("objects", manager)


super()._prepare()


class Meta:
abstract = True




class SModel(models.Model, metaclass=SModelBase):
managers = False


class Meta:
abstract = True

之后,在每个模型中,你只需要导入:

from custom.models import SModel




class SUser(SModel):
pass

views中,你可以这样调用:

SUser.objects.get_if_exist(id=1)

来一片怎么样?它将解析到限制1。

go = Content.objects.filter(name="baby")[0]

我更喜欢这种不使用异常的方法。它既可以处理多个对象,也可以不处理对象。

go_list = Content.objects.filter(name="baby")
if (len(go_list) == 1):
go = go_list[0]
else:
go = None # optionally do other things if there are multiple objects / no objects.