关于python:处理Django的objects.get的最佳方法是什么?

What's the best way to handle Django's objects.get?

每当我这样做:

1
thepost = Content.objects.get(name="test")

当找不到任何东西时,它总是抛出一个错误。我该怎么处理?


1
2
3
4
try:
    thepost = Content.objects.get(name="test")
except Content.DoesNotExist:
    thepost = None

使用模型不存在异常


通常,使用django快捷方式函数get_object_or_404而不是直接使用API更有用:

1
2
3
from django.shortcuts import get_object_or_404

thepost = get_object_or_404(Content, name='test')

很明显,如果找不到对象,这将引发404错误,如果成功,代码将继续。


你也可以抓住一个普通的实干主义者。根据http://docs.djangoproject.com/en/dev/ref/models/queryset上的文档/

1
2
3
4
5
6
from django.core.exceptions import ObjectDoesNotExist
try:
    e = Entry.objects.get(id=3)
    b = Blog.objects.get(id=1)
except ObjectDoesNotExist:
    print"Either the entry or blog doesn't exist."

另一种写作方式:

1
2
3
4
try:
    thepost = Content.objects.get(name="test")
except Content.DoesNotExist:
    thepost = None

简单地说:

1
thepost = Content.objects.filter(name="test").first()

请注意,两者并非完全相同。Manager方法get不仅在没有您要查询的记录的情况下会引发异常,而且在发现多个记录时也会引发异常。当有多个记录时,使用first可能会通过返回第一个记录而悄悄地破坏业务逻辑。


捕获异常

1
2
3
4
try:
    thepost = Content.objects.get(name="test")
except Content.DoesNotExist:
    thepost = None

或者,您可以筛选,如果没有匹配的内容,它将返回空列表。

1
2
3
posts = Content.objects.filter(name="test")
if posts:
    # do something with posts[0] and see if you want to raise error if post > 1


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

1
2
3
4
5
6
class ContentManager(model.Manager):
    def get_nicely(self, **kwargs):
        try:
            return self.get(kwargs)
        except(KeyError, Content.DoesNotExist):
            return None

然后将其包含在内容模型类中

1
2
3
class Content(model.Model):
    ...
    objects = ContentManager()

这样,可以很容易地在视图中处理它,即

1
2
3
4
5
post = Content.objects.get_nicely(pk = 1)
if post != None:
    # Do something
else:
    # This post doesn't exist


引发http404异常非常有效:

1
2
3
4
5
6
7
8
from django.http import Http404

def detail(request, poll_id):
    try:
        p = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404
    return render_to_response('polls/detail.html', {'poll': p})