获取对象时如何处理“匹配查询不存在”
Posted
技术标签:
【中文标题】获取对象时如何处理“匹配查询不存在”【英文标题】:How to handle "matching query does not exist" when getting an object 【发布时间】:2016-01-12 04:44:54 【问题描述】:当我想用 get() 函数选择对象时
personalProfile = World.objects.get(ID=personID)
如果 get 函数没有返回 find 值,则“匹配查询不存在”。发生错误。
如果我不需要这个错误,我会使用 try 和 except 函数
try:
personalProfile = World.objects.get(ID=personID)
except:
pass
但我认为这不是最好的方法,因为我使用了
except:
pass
请推荐一些想法或代码示例来解决这个问题
【问题讨论】:
【参考方案1】:get_or_none()
函数现在是 proposed、multiple times。拒绝通知是功能蠕变,您可能同意也可能不同意。该功能在 first()
查询集方法中存在——语义略有不同。
但首先要做的是:
当找不到World
对象时,经理抛出World.DoesNotExist
,ObjectDoesNotExist
的一个专门子类:
try:
personalProfile = World.objects.get(ID=personID)
except World.DoesNotExist:
pass
还有get_object_or_404()
在找不到对象时引发Http404
异常。
您也可以创建自己的get_or_none()
。一个可能的实现可能是:
def get_or_none(queryset, *args, **kwargs):
try:
return queryset.get(*args, **kwargs)
except ObjectDoesNotExist:
return None
请注意,当找到多个匹配对象时,这仍然会引发MultipleObjectsReturned
。如果您总是想要第一个对象而不考虑其他对象,您可以使用first()
进行简化,当查询集为空时返回None
:
def get_or_none(queryset, *args, **kwargs):
return queryset.filter(*args, **kwargs).first()
但是请注意,要使其可靠地工作,您需要正确的对象顺序,因为在存在多个对象时first()
可能是不确定的(它可能从用于过滤的数据库索引中返回第一个对象查询,索引和基础表都不需要排序,甚至没有可重复的顺序)。
但是,仅当使用检索对象对于进一步的程序流程而言是严格可选的时才使用两者。如果无法检索对象是错误,请使用get_object_or_404()
。当一个对象不存在时应该创建它,使用get_or_create()
。在这些情况下,两者都更适合简化程序流程。
【讨论】:
Django 1.6 中添加的first()
方法与get_or_none
非常相似。请注意,您没有在方法中处理MultipleObjectsReturned
。 first()
方法只取第一个元素,而忽略其余部分。
@Alasdair 不处理MultipleObjectsReturned
是故意的。但是,是的,get_or_none()
可以简化为使用first()
。您是否检查过它如何影响生成的 SQL 查询?
我的观点是,虽然您链接的票证因无法修复而关闭,但最终添加了该功能,但名称不同。 MyModel.objects.filter(**kwargs).first()
做同样的事情 get_object_or_none(MyModel, **kwargs)
,除非你真的关心 MultipleObjectsReturned
(我希望大多数时候你不关心)。我没有检查过 SQL,但我希望它会非常相似,可能与 limit
有一些不同。
@Alasdair 嗯,我认为这取决于你想要什么语义。我真的很关心MultipleObjectsReturned
。当有多个对象与过滤器匹配并且我只想要一个时,first()
可能会不确定地返回其中的任何一个,具体取决于底层查询集是否已排序。如果发生这种情况时更喜欢 django 大声而清晰地向我吠叫 ;)。
当然,我知道处理MultipleObjectsReturned
有时很重要,这就是我一开始提到它的原因。在这些情况下,您需要一个 try except 块来处理它,在这种情况下,我宁愿使用get()
,而不是使用get_or_none()
快捷方式来处理一个可能的异常而不是另一个。【参考方案2】:
这取决于如果它不存在你想做什么..
有get_object_or_404
:
在给定模型管理器上调用 get(),但它引发 Http404 而不是模型的 DoesNotExist 异常。
get_object_or_404(World, ID=personID)
除了你当前做的代码之外,这与尝试非常接近。
否则有get_or_create
:
personalProfile, created = World.objects.get_or_create(ID=personID)
不过,如果您选择继续当前的方法,至少要确保异常已本地化为正确的错误,然后根据需要对其进行处理
try:
personalProfile = World.objects.get(ID=personID)
except MyModel.DoesNotExist:
raise Http404("No MyModel matches the given query.")
上面的 try/except 句柄类似于在文档中找到的 get_object_or_404...
【讨论】:
感谢您的帮助。我尝试这个并得到错误,因为我没有导入 Http404 然后通过“from django.http import Http404”修复这个并完美!以上是关于获取对象时如何处理“匹配查询不存在”的主要内容,如果未能解决你的问题,请参考以下文章
当 RabbitMQ 交换不存在时如何处理错误(并且消息通过消息传递网关接口发送)