Django:从DB获取一个对象,如果没有匹配则为"None"

Dav*_*ver 99 python django

是否有任何Django函数可以让我从数据库中获取一个对象,如果没有匹配则有None?

现在我正在使用类似的东西:

foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None
Run Code Online (Sandbox Code Playgroud)

但这不是很清楚,到处都是凌乱的.

Nic*_*ood 138

有两种方法可以做到这一点;

try:
    foo = Foo.objects.get(bar=baz)
except model.DoesNotExist:
    foo = None
Run Code Online (Sandbox Code Playgroud)

或者您可以使用包装器:

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

像这样称呼它

foo = get_or_none(Foo, baz=bar)
Run Code Online (Sandbox Code Playgroud)

  • 这就是Python迭代的工作原理(提出了一个StopIteration),这是该语言的核心部分.我不是尝试/除功能的忠实粉丝,但它似乎被认为是Pythonic. (18认同)
  • 我不喜欢它使用功能异常的事实 - 这在大多数语言中都是不好的做法.在python中怎么样? (8认同)
  • @pcv:关于"大多数"语言没有可靠的传统智慧.我想你会想到你碰巧使用的某种特定语言,但要注意这些量词.与Python中的任何事情一样,例外情况可能同样缓慢(或"足够快").回到问题 - 这是框架的一个缺点,他们没有提供任何`queryset`方法在1.6之前做到这一点!但至于这个结构 - 它只是笨拙.它不是"邪恶的",因为你最喜欢的语言的一些教程作者这么说.试试谷歌:"请求宽恕而不是许可". (4认同)

Ces*_*ssa 87

在Django 1.6中,您可以使用first()Queryset方法.它返回查询集匹配的第一个对象,如果没有匹配的对象则返回None.

用法:

p = Article.objects.order_by('title', 'pub_date').first()
Run Code Online (Sandbox Code Playgroud)

  • @sleepycal我不同意.`first()`完全按照它的设想工作.它返回查询结果中的第一个对象,并不关心是否找到多个结果.如果需要检查返回的多个对象,则应使用`.get()`代替. (24认同)
  • 这不是一个好的答案,如果找到多个对象,则不会引发`MultipleObjectsReturned()`,如[here](https://docs.djangoproject.com/en/1.2/ref/exceptions/#multipleobjectsreturned)所述.你可以找到一些更好的答案[这里](http://stackoverflow.com/questions/3090302/in-django-how-do-i-objects-get-but-return-none-when-nothing-is-found) (18认同)
  • 如果您的数据库约束没有正确地管理跨对象的唯一性,那么您可以遇到逻辑期望只有一个对象(由first()选择)的边缘情况,但实际上存在多个对象.使用get()而不是first()通过引发`MultipleObjectsReturned()`为您提供额外的保护层.如果返回的结果不会返回多个对象,则不应将其视为这样.关于这个[这里]有一个*很长的争论(https://groups.google.com/forum/#!msg/django-developers/h50RLblVDU8/1fhPK_IcjZMJ) (12认同)
  • [编辑]正如OP所说,`.get()`不适合他的需要.@kaapstorm可以在下面找到这个问题的正确答案,显然是更合适的答案.以这种方式滥用`filter()`会导致意想不到的后果,OP可能没有意识到(除非我在这里遗漏了一些东西) (7认同)

kaa*_*orm 83

为sorki的答案添加一些示例代码(我将其添加为评论,但这是我的第一篇文章,我没有足够的声誉留下评论),我实现了一个get_or_none自定义管理器,如下所示:

from django.db import models

class GetOrNoneManager(models.Manager):
    """Adds get_or_none method to objects
    """
    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except self.model.DoesNotExist:
            return None

class Person(models.Model):
    name = models.CharField(max_length=255)
    objects = GetOrNoneManager()
Run Code Online (Sandbox Code Playgroud)

现在我可以这样做:

bob_or_none = Person.objects.get_or_none(name='Bob')
Run Code Online (Sandbox Code Playgroud)

  • 这应该是正确/可接受的答案. (4认同)

lla*_*aro 13

你也可以尝试使用django烦人(它有另一个有用的功能!)

安装它:

pip install django-annoying

from annoying.functions import get_object_or_None
get_object_or_None(Foo, bar=baz)
Run Code Online (Sandbox Code Playgroud)


sor*_*rki 9

给Foo 定制经理.这很简单 - 只需将代码放入自定义管理器中,在模型中设置自定义管理器并调用它即可Foo.objects.your_new_func(...).

如果你需要泛型函数(在任何模型上使用它而不仅仅是使用自定义管理器)编写自己的函数并将它放在你的python路径上的某个地方并导入,而不是凌乱.