この例外をどのようにキャッチしますか?


162

このコードは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

おそらくそれが理由です。


どのようにインポートしましたrelatedか?
John Zwinck、2014年

4
AttributeError代わりに使用related.ReverseSingleRelatedObjectDescriptor.RelatedObjectDoesNotExist
キャサリン2014年

はい@JohnZwinck関連をインポートしました。
ボートコーダー2014年

回答:


302

関連するモデルが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そのモデルの存在しない例外になります。


7
バグはDjangoRestFrameworkにあり、モデルはその時点ではやや困難です。ObjectDoesNotExistをキャッチすることにしました。
ボートコーダー、2014年

3
AttributeErrorを使用することもできます。これは、特定の状況下でより適切なオプションになる場合があります(このエラーは、ほとんどの場合、レコードの「属性」にアクセスしているときに発生するため、この方法では、この属性が記録か否か
ジョーダン・ライター

1
ええええええ。しかし、なぜNoneを返せないのでしょうか?特に1対1のフィールドでは。それとも正当な理由がありますか?
Neil、

61

関連するモデルクラスをインポートしたくない場合は、次のことができます。

except MyModel.related_field.RelatedObjectDoesNotExist:

または

except my_model_instance._meta.model.related_field.RelatedObjectDoesNotExist:

どこrelated_fieldのフィールド名です。


7
これは、循環インポートを回避する必要がある場合に非常に便利です。ありがとう
Giovanni Di Milia

40

この例外を一般的にキャッチするには、次のようにします

from django.core.exceptions import ObjectDoesNotExist

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

2
私はこれが実際にエラーを期待どおりにキャッチしていないことを発見しました。<Model>.DoesNotExistやった
エリック・ブラム

1
@EricBlum <Model> .DoesNotExistはObjectDoesNotExistの子孫であるため、これは発生しません。なぜそれが起こっているのかを掘り下げたり、コードの詳細を説明したりできますか?
ザグス18年

10

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>.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>.DoesNotExistObjectDoesNotExist(からのインポートdjango.core.exceptions)、またはAttributeErrorあなたの文脈の中で最も理にかなっているものは何でも、。


2

tdelaneyの答えは通常のコードパスに最適ですが、この例外をテストでキャッチする方法を知る必要がある場合:

from django.core.exceptions import ObjectDoesNotExist

...

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

2

少し遅れますが、他の人に役立ちます。

これを処理する2つの方法。

1日:

例外をキャッチする必要がある場合

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

2番目: 例外を処理したくない場合

>>> hasattr(p2, 'restaurant')
False
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.