在使用Django的ORM时,在什么时候引发了异常

Tom*_*tie 6 django django-orm

足够简单的例子 - 我有一些以查询集开头的Django代码......

queryset = MyModel.objects.all()
Run Code Online (Sandbox Code Playgroud)

稍后它会执行各种过滤,具体取决于一些可配置的选项......

if something:
    queryset = self.queryset.filter(foo=some_foo)

if another_thing:
    queryset = self.queryset.filter(bar=some_bar)
Run Code Online (Sandbox Code Playgroud)

最后它执行查找...

try:
    obj = queryset.get()
except ObjectDoesNotExist:
    raise ValidationError('Does not exist')
Run Code Online (Sandbox Code Playgroud)

现在,由于过滤需要灵活的方式发生,some_foo或者some_bar变量可能不是正确的类型(例如,我们最终会得到一个空字符串,试图过滤整数字段.)所以它是可能的为此代码最终提出一个TypeError或一个ValueError.

那很好,我可以适当地处理这个案子,但是我从ORM合同中不清楚的是,我应该在什么时候期望提出这些例外.

  • 它会在.filter()声明中出现吗?...
  • ......还是在.get()声明上?......
  • ......或者处于未指定状态,我处理它是否能够发生?(例如,可能取决于数据库后端的实现?)

bri*_*anz 1

为了回答最初的问题,当构建新的查询集时,在调用过滤器时会引发FieldError和:ValueError

>>> a = Account.objects.all()
>>> a = a.filter(id=3)
>>> a = a.filter(no_exist=3)
<snip>
FieldError: Cannot resolve keyword 'no_exist' into field. Choices are: active, created_on, group, id, ...

>>> a = Account.objects.all()
>>> a = a.filter(id='abc')
ValueError: invalid literal for int() with base 10: 'abc'
Run Code Online (Sandbox Code Playgroud)

我还要补充一点,这种模式对我来说似乎具有误导性,因为它filter通常用于返回模型的列表/可迭代,而不是get. 为了清楚和更容易地处理异常,我建议使用这种模式:

>>> a = Account.objects.all()
>>> a = a.filter(id=3)
>>> a = a.filter(no_exist=3)
<snip>
FieldError: Cannot resolve keyword 'no_exist' into field. Choices are: active, created_on, group, id, ...

>>> a = Account.objects.all()
>>> a = a.filter(id='abc')
ValueError: invalid literal for int() with base 10: 'abc'
Run Code Online (Sandbox Code Playgroud)

另一个额外的好处是,IIRC,克隆查询集的工作相对昂贵,因此您可以忽略该开销,同时使代码更清晰。回到你的问题,使用这种模式,毫无疑问会在哪里引发异常。