如何捕捉这个异常?

这段代码在 django/db/model/fields.py 中它创建/定义了一个异常?

class ReverseSingleRelatedObjectDescriptor(six.with_metaclass(RenameRelatedObjectDescriptorMethods)):
# This class provides the functionality that makes the related-object
# managers available as attributes on a model class, for fields that have
# a single "remote" value, on the class that defines the related field.
# In the example "choice.poll", the poll attribute is a
# ReverseSingleRelatedObjectDescriptor instance.
def __init__(self, field_with_rel):
self.field = field_with_rel
self.cache_name = self.field.get_cache_name()


@cached_property
def RelatedObjectDoesNotExist(self):
# The exception can't be created at initialization time since the
# related model might not be resolved yet; `rel.to` might still be
# a string model reference.
return type(
str('RelatedObjectDoesNotExist'),
(self.field.rel.to.DoesNotExist, AttributeError),
{}
)

这是在 django/db/model/fields/related.py 中,它引发了上面提到的异常:

def __get__(self, instance, instance_type=None):
if instance is None:
return self
try:
rel_obj = getattr(instance, self.cache_name)
except AttributeError:
val = self.field.get_local_related_value(instance)
if None in val:
rel_obj = None
else:
params = dict(
(rh_field.attname, getattr(instance, lh_field.attname))
for lh_field, rh_field in self.field.related_fields)
qs = self.get_queryset(instance=instance)
extra_filter = self.field.get_extra_descriptor_filter(instance)
if isinstance(extra_filter, dict):
params.update(extra_filter)
qs = qs.filter(**params)
else:
qs = qs.filter(extra_filter, **params)
# Assuming the database enforces foreign keys, this won't fail.
rel_obj = qs.get()
if not self.field.rel.multiple:
setattr(rel_obj, self.field.related.get_cache_name(), instance)
setattr(instance, self.cache_name, rel_obj)
if rel_obj is None and not self.field.null:
raise self.RelatedObjectDoesNotExist(
"%s has no %s." % (self.field.model.__name__, self.field.name)
)
else:
return rel_obj

问题是这个代码:

    try:
val = getattr(obj, attr_name)
except related.ReverseSingleRelatedObjectDescriptor.RelatedObjectDoesNotExist:
val = None  # Does not catch the thrown exception
except Exception as foo:
print type(foo)  # Catches here, not above

不会抓住那个例外

>>>print type(foo)
<class 'django.db.models.fields.related.RelatedObjectDoesNotExist'>
>>>isinstance(foo, related.FieldDoesNotExist)
False

还有

except related.RelatedObjectDoesNotExist:

产生 AttributeError: 'module' object has no attribute 'RelatedObjectDoesNotExist'

>>>isinstance(foo, related.ReverseSingleRelatedObjectDescriptor.RelatedObjectDoesNotExist)
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types

这可能就是为什么。

79186 次浏览

如果你的相关模型叫 Foo,你可以这样做:

except Foo.DoesNotExist:

姜戈不吓人的时候就很神奇。RelatedObjectDoesNotExist是一个返回在运行时动态计算出的类型的属性。该类型使用 self.field.rel.to.DoesNotExist作为基类。

根据姜戈的文件:

不存在

例外 < strong > Model. DoesNotExist

当预期对象不是 ORM 时,ORM 将引发此异常 例如,当没有对象时,QuerySet.get()将引发它 为给定的查找找到。

Django 提供了一个 DoesNotExist异常作为 每个模型类标识不能为 Find,允许您捕获特定模型类的异常。

异常是 django.core.exceptions.ObjectDoesNotExist的一个子类。

这就是让这一切发生的魔法。一旦建立了模型,self.field.rel.to.DoesNotExist就是该模型不存在的例外。

如果不想导入相关的模型类,可以:

except MyModel.related_field.RelatedObjectDoesNotExist:

或者

except my_model_instance._meta.model.related_field.RelatedObjectDoesNotExist:

其中 related_field是字段名。

假设我们有以下模型:

class MainModel(Model):
pass


class RelatedModel(Model):
main = OneToOneField(MainModel, null=True, related_name="related")

可以使用 MainModel().related获得 RelatedObjectDoesNotExist异常。

有三个选项可以捕获这个异常,可以通过查看异常的 .__class__.__mro__找到它:

  1. MainModel.related.RelatedObjectDoesNotExist
  2. RelatedModel.DoesNotExist
  3. django.core.exceptions.ObjectDoesNotExist

相关的对象不存在

RelatedObjectDoesNotExist是问题所寻找的,但是特定于一个可空的 OneToOneField:

try:
# Your code here
except MainModel.related.RelatedObjectDoesNotExist:
# Handle exception

RelatedModel

Model.DoesNotExistRelatedObjectDoesNotExist的父类。要捕捉它,您需要能够导入有问题的模型,但这是一个更通用的有用代码模式。

try:
# Your code here
except OtherModel.DoesNotExist:
# Handle exception

异常,ObjectDoesNotExist

ObjectDoesNotExistModel.DoesNotExist的父类。这将捕获任何模型的异常,如果您不知道哪个模型将引发异常,这将很有帮助:

from django.core.exceptions import ObjectDoesNotExist


try:
# Your code here
except ObjectDoesNotExist:
# Handle exception

Tdelaney 的答案对于常规代码路径非常有用,但是如果您需要知道如何在测试中捕获这个异常:

from django.core.exceptions import ObjectDoesNotExist


...


def testCompanyRequired(self):
with self.assertRaises(ObjectDoesNotExist):
employee = Employee.objects.create()

RelatedObjectDoesNotExist异常是在运行时动态创建的。下面是 ForwardManyToOneDescriptorReverseOneToOneDescriptor描述符的相关代码片段:

@cached_property
def RelatedObjectDoesNotExist(self):
# The exception can't be created at initialization time since the
# related model might not be resolved yet; `self.field.model` might
# still be a string model reference.
return type(
'RelatedObjectDoesNotExist',
(self.field.remote_field.model.DoesNotExist, AttributeError),
{}
)

所以这个异常继承自 <model name>.DoesNotExistAttributeError。事实上,这个异常类型的完整 MRO 是:

[<class 'django.db.models.fields.related_descriptors.RelatedObjectDoesNotExist'>,
<class '<model module path>.DoesNotExist'>,
<class 'django.core.exceptions.ObjectDoesNotExist'>,
<class 'AttributeError'>,
<class 'Exception'>,
<class 'BaseException'>,
<class 'object'>]

最基本的要点是,您可以捕捉 <model name>.DoesNotExistObjectDoesNotExist(从 django.core.exceptions导入)或 AttributeError,任何在您的上下文中最有意义的内容。

有点晚了,但对别人有帮助。

两种处理方法。

第一名:

当我们需要捕捉异常时

>>> from django.core.exceptions import ObjectDoesNotExist
>>> try:
>>>     p2.restaurant
>>> except ObjectDoesNotExist:
>>>     print("There is no restaurant here.")
There is no restaurant here.

第二名: 当不想处理异常时

>>> hasattr(p2, 'restaurant')
False