このコードはDjango/db/models/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/models/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
これがおそらく理由です。
関連するモデルがFooと呼ばれる場合は、次のようにします。
except Foo.DoesNotExist:
Djangoは恐ろしいものではないのに驚くばかりです。 RelatedObjectDoesNotExist
は、実行時に動的に計算される型を返すプロパティです。そのタイプは、self.field.rel.to.DoesNotExist
を基本クラスとして使用します。 Djangoドキュメントによると:
ObjectDoesNotExistおよびDoesNotExist
例外DoesNotExist
DoesNotExist例外は、クエリの特定のパラメーターに対してオブジェクトが見つからない場合に発生します。 Djangoは、各モデルクラスの属性としてDoesNotExist例外を提供して、見つからなかったオブジェクトのクラスを識別し、許可します。
try
/except
で特定のモデルクラスをキャッチします。
これがそれを実現する魔法です。モデルが構築されると、self.field.rel.to.DoesNotExist
はそのモデルの存在しない例外です。
関連するモデルクラスをインポートしたくない場合は、次のことができます。
except MyModel.related_field.RelatedObjectDoesNotExist:
または
except my_model_instance._meta.model.related_field.RelatedObjectDoesNotExist:
ここで、related_field
はフィールド名です。
一般的にこの例外をキャッチするには、次のようにします
from Django.core.exceptions import ObjectDoesNotExist
try:
# Your code here
except ObjectDoesNotExist:
# Handle exception
RelatedObjectDoesNotExist
例外は、実行時に動的に作成されます。 ForwardManyToOneDescriptor
およびReverseOneToOneDescriptor
記述子に関連するコードスニペットを次に示します。
@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>.DoesNotExist
およびAttributeError
から継承します。実際、この例外タイプの完全な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>.DoesNotExist
、ObjectDoesNotExist
(Django.core.exceptions
からインポート)またはAttributeError
をキャッチできることです。
tdelaneyの答えは、通常のコードパスには最適ですが、テストでこの例外をキャッチする方法を知る必要がある場合:
from Django.core.exceptions import ObjectDoesNotExist
...
def testCompanyRequired(self):
with self.assertRaises(ObjectDoesNotExist):
employee = Employee.objects.create()