이 예외를 어떻게 잡습니까?


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

4
AttributeError대신 사용related.ReverseSingleRelatedObjectDescriptor.RelatedObjectDoesNotExist
catherine

예 @JohnZwinck 관련을 가져 왔습니다.
boatcoder

답변:


302

관련 모델의 이름이 Foo 인 경우 다음을 수행하면됩니다.

except Foo.DoesNotExist:

장고는 무섭지 않을 때 놀랍습니다. RelatedObjectDoesNotExist런타임시 동적으로 계산되는 유형을 반환하는 속성입니다. 이 유형은 self.field.rel.to.DoesNotExist기본 클래스로 사용 됩니다. Django 설명서에 따르면 :

ObjectDoesNotExist 및 DoesNotExist

예외 NotNotExist

DoesNotExist의 개체가 쿼리의 주어진 매개 변수를 찾을 수없는 경우 예외가 발생합니다. Django는 찾을 수없는 객체의 클래스를 식별하고 / 로 특정 모델 클래스를 잡을 수 있도록 각 모델 클래스의 속성으로 DoesNotExist 예외를 제공합니다 .tryexcept

이것이 일어나는 마술입니다. 모델이 구축되면 해당 모델에 self.field.rel.to.DoesNotExist대한 존재하지 않는 예외입니다.


7
버그가 DjangoRestFramework에 있었기 때문에 모델은 그 시점에 따라 가기가 다소 어렵습니다. ObjectDoesNotExist를 잡기로 결정했습니다.
보트 코더

3
특정 상황에서 더 나은 옵션 일 수있는 AttributeError를 사용할 수도 있습니다 (이 오류는 레코드의 "속성"에 액세스 할 때 거의 항상 발생하므로이 속성을 통해 해당 속성이 해당 속성에 해당하는지 여부를 추적 할 필요가 없습니다. 기록 여부.
요르단 라이터에게

1
그래 알았어 그러나 왜 None을 반환 할 수 없습니까? 특히 일대일 필드의 경우. 아니면 좋은 이유가 있습니까?
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의 자손이므로 발생하지 않아야합니다. 왜 이런 일이 일어나고 있는지 또는 코드에 대한 자세한 내용을 알려줄 수 있습니까?
Zags

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>.DoesNotExist, ObjectDoesNotExist(가져 오기 django.core.exceptions) 또는 AttributeError당신의 상황에서 가장 의미가 무엇이든,.


2

tdelaney의 답변은 일반적인 코드 경로에 유용하지만 테스트 에서이 예외를 포착하는 방법을 알아야하는 경우 :

from django.core.exceptions import ObjectDoesNotExist

...

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

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.