Python Django:从数据库中获取对象,或';无';如果没有匹配
是否有任何Django函数可以让我从数据库中获取对象,或者如果没有匹配的对象,则没有 现在我用的是这样的东西:Python Django:从数据库中获取对象,或';无';如果没有匹配,python,django,Python,Django,是否有任何Django函数可以让我从数据库中获取对象,或者如果没有匹配的对象,则没有 现在我用的是这样的东西: foo = Foo.objects.filter(bar=baz) foo = len(foo) > 0 and foo.get() or None 但这还不是很清楚,到处都是,这很混乱。有两种方法可以做到这一点 try: foo = Foo.objects.get(bar=baz) except model.DoesNotExist: foo = None
foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None
但这还不是很清楚,到处都是,这很混乱。有两种方法可以做到这一点
try:
foo = Foo.objects.get(bar=baz)
except model.DoesNotExist:
foo = None
或者您可以使用包装器:
def get_or_none(model, *args, **kwargs):
try:
return model.objects.get(*args, **kwargs)
except model.DoesNotExist:
return None
这样说吧
foo = get_or_none(Foo, baz=bar)
给福。这很简单-只需将代码放入自定义管理器的函数中,在模型中设置自定义管理器,并使用Foo.objects.your_new_func(…)
调用它即可
如果您需要泛型函数(在任何模型上使用它,而不仅仅是在自定义管理器上),请编写自己的函数,并将其放置在python路径上的某个位置进行导入,不再凌乱。要在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()
现在我可以做到:
bob_or_none = Person.objects.get_or_none(name='Bob')
无论是通过管理器还是泛型函数执行此操作,您可能还希望在TRY语句中捕获“multipleObjectsReturn”,因为如果kwargs检索到多个对象,get()函数将引发此问题 基于通用功能:
def get_unique_or_none(model, *args, **kwargs):
try:
return model.objects.get(*args, **kwargs)
except (model.DoesNotExist, model.MultipleObjectsReturned), err:
return None
在经理中:
class GetUniqueOrNoneManager(models.Manager):
"""Adds get_unique_or_none method to objects
"""
def get_unique_or_none(self, *args, **kwargs):
try:
return self.get(*args, **kwargs)
except (self.model.DoesNotExist, self.model.MultipleObjectsReturned), err:
return None
在Django1.6中,可以使用
first()
Queryset方法。它返回queryset匹配的第一个对象,如果没有匹配的对象,则返回None
用法:
p = Article.objects.order_by('title', 'pub_date').first()
您也可以尝试使用django(它还有另一个有用的功能!) 安装时请使用:
pip install django-annoying
from annoying.functions import get_object_or_None
get_object_or_None(Foo, bar=baz)
以下是helper函数的一个变体,允许您有选择地传入
QuerySet
实例,以防您希望从模型的all
objects QuerySet以外的QuerySet(例如,从属于父实例的子项的子集)获取唯一对象(如果存在):
这可以通过两种方式使用,例如:
obj=get\u unique\u或\u none(Model,*args,**kwargs)
如前所述obj=get\u unique\u或\u none(Model、parent.children、*args、**kwargs)
我认为在大多数情况下,您可以使用:
foo, created = Foo.objects.get_or_create(bar=baz)
只有当在Foo表中添加一个新条目并不重要时(其他列将具有None/默认值)我不喜欢它对功能使用异常的事实-这在大多数语言中都是一种不好的做法。这在python中是如何实现的?这就是python迭代的工作方式(引发StopIteration),这是该语言的核心部分。我也不是try/except功能的超级粉丝,但它似乎被认为是python的。@pcv:“大多数”语言都没有可靠的传统智慧。我想你会考虑一些你碰巧使用的特定语言,但要小心使用这些量词。异常可以和Python中的任何东西一样慢(或“足够快”)。回到问题上来——这是框架的一个缺点,在1.6之前,他们没有提供任何
queryset
方法来实现这一点!但对于这个结构来说,它只是笨拙。这不是“邪恶”,因为你最喜欢的语言的一些教程作者这样说。试试谷歌:“请求原谅而不是允许”。@TomaszGandor:是的,不管你最喜欢的语言教程怎么说,它都很笨拙,很难阅读。当我看到一个异常时,我认为发生了一些不标准的事情。可读性很重要。但是我同意当没有其他合理的选择时,你应该去做,不会有什么不好的事情发生。@pcvget
方法不应该返回None
,因此异常是有意义的。您应该在确定对象将在那里/对象“应该”在那里的情况下使用它。同样,使用这样的异常也被认为是“好的”,因为它是有意义的。您需要一个具有不同协定的get
,因此您可以捕获异常并抑制它,这是您所追求的更改。您知道您可以使用foo=foo[0]如果foo-else-NonePython有一个三元运算符,则不必使用布尔运算符。另外,:“注意:如果您只想确定集合中的记录数,就不要在QuerySet上使用len()。使用SQL的SELECT count()在数据库级别处理计数要高效得多,Django正是出于这个原因提供了count()方法。”。重写:foo=foo[0]如果foo.exists(),则没有
可能重复的@mustafa.0x,我认为这不适用于这里。在这里,检查计数将运行另一个查询。然后我们需要再次查询以获得实际数据。在这种情况下,过滤和计数会更有意义。。。但这并不比过滤和调用first()
:p这不是一个好的答案,如果找到多个对象,则不会引发MultipleObjectsReturned()
。你可以找到更好的答案@sleepycal我不同意。first()。它返回查询结果中的第一个对象,不关心是否找到多个结果。如果需要检查返回的多个对象,则应使用.get()
。[编辑]正如OP所说,.get()
不适合他的需要。这个问题的正确答案可以在下面的@kaapstorm中找到,显然是更合适的答案。滥用filter()
这种方式可能会导致意外后果,OP可能没有意识到(除非我在这里遗漏了什么)@sleepycal这种方法会产生什么意外后果?如果您的数据库约束不能正确管理对象之间的唯一性,然后,您可以遇到逻辑预期只有一个对象(由first()选择)但实际上存在多个对象的边缘情况。使用get()而不是first()可以通过提升多个对象return()
为您提供额外的保护层。如果返回的结果为n
foo, created = Foo.objects.get_or_create(bar=baz)