在Django视图中,如何验证对象是否存在而不返回404错误?

107

我需要验证一个对象是否存在并返回该对象,然后根据此执行操作。没有返回404的正确方法是什么?

try:
    listing = RealEstateListing.objects.get(slug_url = slug)
except:
    listing = None

if listing:

1
Rasiel,我能建议你考虑接受另一个答案吗?它似乎是正确的做法,并且比被接受的答案得到了更多的赞同。 - Azendale
1
我可以考虑这个,但是exists是在Django 1.2中引入的,该版本于2010年5月17日发布。如果您注意到我的问题是在09年提交的...那时候这是正确的答案。如果现在认为Exists()是最好的方法,我想选择第二个答案在语义上应该是正确的,对吗? - Rasiel
Rasiel,那时选择那个答案是有道理的。但是stackoverflow网站似乎与解决人们问题一样重要的是建立一组良好/官方问题和最佳答案,因此我建议选择现在被认为是“官方正确”的答案。 - Azendale
if listing: 应该改为 else: - Chronial
4个回答

228
您也可以这样做:
if not RealEstateListing.objects.filter(slug_url=slug).exists():
    # do stuff...
有时候使用try: except:块更加清晰,而其他情况下,一行代码的exists()看起来更清晰...所有这些都取决于你的应用逻辑。

11
.exists() 更快: https://docs.djangoproject.com/en/dev/ref/models/querysets/#exists - fjsj
8
这是更好的方法,应该得到答案。 - Jharwood
4
我理解您的意思是:exists() 方法不能与 get() 方法一起使用,对吗? - Eduard Luca
9
请注意,此解决方案仅在您不打算使用涉及的对象时才有效。否则(如在问题提交者的情况下),它是错误的,并且比已接受的解决方案慢得多:如果您稍后执行 get() 操作,它将向数据库发送第二个查询。 - Chronial
1
如果你想检查对象是否存在并进行相关操作,我会更倾向于使用try-except而不是exists() - Jithin Pavithran
显示剩余2条评论

128

如果没有收到404,我不会使用404包装器,因为这是滥用意图。相反,只需捕获DoesNotExist异常即可。

try:
    listing = RealEstateListing.objects.get(slug_url=slug)
except RealEstateListing.DoesNotExist:
    listing = None

+1:如果您不想要404,那么这比已接受的解决方案更好。 - Carl Meyer
是的,这似乎是更好的解决方案。 - Rasiel
3
如果您需要对对象执行某些操作,那么此解决方案比exists()更好。 - SaeX
2
我喜欢添加 values_list('id', flat=True)。如果我只需要查看是否存在,则可以使用以下代码:listing = RealEstateListing.objects.values_list('id', flat=True).get(slug_url=slug) - erajuan
1
我觉得这个语法奇怪的地方在于 RealEstateListing.DoesNotExist 引用了模型本身,而不是对象本身。为什么不是 RealEstateListing.objects.get(slug_url=slug).DoesNotExist 呢? - Max Vallee

9
listing = RealEstateListing.objects.filter(slug_url=slug).first() 

2
如果您需要稍后使用潜在对象,则此方法是最佳解决方案,因为它仅需要一个赋值,并且避免了使用try/except块。请注意,您可以通过if listing:简单地测试存在性。 - Michael Hays
避免使用try/except是不好的做法。软件开发中最重要的方面之一是控制异常,以便能够提供良好的用户体验。让人们知道当某些东西不能正常工作时。其次,如果您想测试QuerySet的存在,请使用.exists(),否则它是一个对象。使用它们的主键测试存在性....if object.pk: // 运行代码()这个查询比检索对象的所有数据要快得多。你只想知道是否存在。 - Wolfgang Leon
2
已经有一种使用try/except和.exists()的解决方案了。我认为在SO上有多个不同的答案来解决问题是一个好主意。也许这对那些想要使用对象(如果存在)的人来说更好。我不会制定任何规则,以确定是否应避免使用try/except。有时候它很好用,有时候它不好用,例如,如果你只想编写非常紧凑的代码。 - Henrik Heino

0
我会简单地按照以下方式完成:
listing = RealEstateListing.objects.filter(slug_url=slug)
if listing:
    # do stuff

我认为不需要使用try/catch。如果结果中可能有多个对象,请像用户Henrik Heino所示使用first()。


除非在查询集上执行 .first() 或在条件语句中执行 .first(),否则这将始终返回 True。 - B.Adler
在 Django 中,not true 或一个空的 queryset 都等同于 False。 - Reed Jones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接