如果对象存在,如何获取对象,如果不存在则为None?

TIM*_*MEX 193 python django django-queryset

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

go = Content.objects.get(name="baby")
Run Code Online (Sandbox Code Playgroud)

相反的DoesNotExist,我怎么能有go可以None代替?

Art*_*ert 289

没有"内置"方式来做到这一点.Django每次都会引发DoesNotExist异常.在python中处理这个问题的惯用方法是将它包装在try catch中:

try:
    go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
    go = None
Run Code Online (Sandbox Code Playgroud)

我所做的,是子类models.Manager,创建一个safe_get类似上面的代码,并将该管理器用于我的模型.那样你就可以写:SomeModel.objects.safe_get(foo='bar').

  • 这个解决方案是四行长.对我来说这太过分了.使用django 1.6,您可以使用`SomeModel.objects.filter(foo ='bar').first()`这将返回第一个匹配,或者None.如果有几个像`queryset.get()`这样的实例,它不会失败 (158认同)
  • 我认为过度使用处理默认情况的异常是不好的方式.是的,"要求宽恕比获得许可更容易".但在我看来,仍然应该例外地使用异常. (9认同)
  • 显式优于隐式.除非有性能原因要使用`filter().first()`我认为异常是要走的路. (7认同)
  • 很好地使用SomeModel.DoesNotExist而不是导入异常. (6认同)
  • 如果你不关心有倍数,那么使用first()只是一个好主意.否则,这个解决方案是优越的,因为如果您意外地找到多个对象,它仍然会抛出异常,这通常是您希望在这种情况下发生的事情. (5认同)
  • 这比 .first() 更好,因为 .first() 向查询添加了 (sql) order by ,因此该解决方案预计会更快。 (2认同)

Fer*_*xTL 152

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

Content.objects.filter(name="baby").first()
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,如果有多个匹配项,则不会引发错误. (23认同)
  • @colminator我宁愿说guettli应该知道如果他想提高他的stackoverflow reputaiton一个新的答案不属于评论:) FeroxTL应该得到点作为一个答案更明确的隐藏作为一个答案.你认为你的评论对于guettli是足够的,我认为如果这是你的建议,不应该添加到答案中. (7认同)
  • 'FeroxTL'你需要将@guettli归功于这个答案,因为他在你的帖子前一年对你接受的答案进行了评论. (5认同)
  • @Joakim我发布一个新的"答案"没问题 - 只是为了给予应有的信用:-) (3认同)
  • 与公认的答案相比,这种方法的效果如何? (3认同)
  • 我喜欢这个解决方案,因为使用`objecst.get()`推断我们知道数据库中有一个或没有. (2认同)
  • @MaxCore我认为你是对的。`.first()` 在查询中添加了一个 `order by`,因此会变慢。 (2认同)
  • 我刚刚分析了 600 次迭代的循环。通过用 get 替换 .first(),循环的执行时间现在快了 3 倍(postgres),并且剩下的很多都是分析开销。get() 快了很多。 (2认同)

Ama*_*osh 32

来自django docs

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
Run Code Online (Sandbox Code Playgroud)


Ran*_*u R 28

您可以为此创建一个通用函数.

def get_or_none(classmodel, **kwargs):
    try:
        return classmodel.objects.get(**kwargs)
    except classmodel.DoesNotExist:
        return None
Run Code Online (Sandbox Code Playgroud)

使用如下:

go = get_or_none(Content,name="baby")
Run Code Online (Sandbox Code Playgroud)

如果没有条目匹配则go将为None否则将返回Content条目.

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


Gau*_*rav 15

你可以这样做:

go  = Content.objects.filter(name="baby").first()
Run Code Online (Sandbox Code Playgroud)

现在go变量可以是你想要的对象,也可以是None

参考:https://docs.djangoproject.com/en/1.8/ref/models/querysets/#django.db.models.query.QuerySet.first


Mot*_*ski 13

为了方便起见,这里是我编写的代码片段,基于这里精彩回复的输入:

class MyManager(models.Manager):

    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except ObjectDoesNotExist:
            return None
Run Code Online (Sandbox Code Playgroud)

然后在你的模型中:

class MyModel(models.Model):
    objects = MyManager()
Run Code Online (Sandbox Code Playgroud)

而已.现在你有MyModel.objects.get()以及MyModel.objetcs.get_or_none()

  • 另外,不要忘记导入:从django.core.exceptions导入ObjectDoesNotExist (7认同)

Rya*_*axe 12

你可以使用exists过滤器:

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

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

  • 如果存在,那将导致额外的数据库调用。这不是一个好主意 (3认同)
  • @克里斯托弗我认为你是对的。现在,我再次阅读问题,OP实际上希望返回实际的对象。因此,在获取对象之前,`exists()`将与`if`子句一起使用,从而导致对数据库的双重打击。我仍然会保留评论,以免对他人有所帮助。 (2认同)

小智 9

也许你使用更好:

User.objects.filter(username=admin_username).exists()
Run Code Online (Sandbox Code Playgroud)

  • 这样做的问题是,如果用户在此行和实际检索它的行之间被删除。 (2认同)

Adi*_*lik 7

在视图中的不同点处理异常真的很麻烦.在models.py文件中定义自定义模型管理器,如

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

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

class Content(model.Model):
    ...
    objects = ContentManager()
Run Code Online (Sandbox Code Playgroud)

通过这种方式,可以在视图中轻松处理,即

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


mkn*_*cht 7

这是您可能不想重新实现的烦人功能之一:

from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")
Run Code Online (Sandbox Code Playgroud)


blh*_*ing 5

如果您想要一个简单的单行解决方案,不涉及异常处理、条件语句或 Django 1.6+ 的要求,请改为执行以下操作:

x = next(iter(SomeModel.objects.filter(foo='bar')), None)
Run Code Online (Sandbox Code Playgroud)


Moh*_*eza 5

我认为使用这个主意不错 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)
Run Code Online (Sandbox Code Playgroud)

这个例子相当于:

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.")
Run Code Online (Sandbox Code Playgroud)

您可以在 Django 在线文档中阅读有关get_object_or_404() 的更多信息。