Bu istisnayı nasıl yakalarsınız?


162

Bu kod django / db / models / fields.py dosyasındadır Bir istisna oluşturur / tanımlar?

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),
            {}
        )

Bu, django / db / models / fields / related.py dosyasındadır ve yukarıda belirtilen istisnayı artırır:

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

Sorun şu ki bu kod:

    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

bu istisnayı yakalamayacak

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

ve

except related.RelatedObjectDoesNotExist:

Yükseltir 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

muhtemelen nedeni budur.


Nasıl ithal ettin related?
John Zwinck

4
AttributeErroryerine kullanmakrelated.ReverseSingleRelatedObjectDescriptor.RelatedObjectDoesNotExist
catherine

Evet @ JohnZwinck ile ilgili ithal.
boatcoder

Yanıtlar:


302

İlgili modelinize Foo adı verilirse şunları yapabilirsiniz:

except Foo.DoesNotExist:

Django, korkunç olmadığı zaman inanılmaz. RelatedObjectDoesNotExistçalışma zamanında dinamik olarak hesaplanan bir tür döndüren bir özelliktir. Bu tür self.field.rel.to.DoesNotExisttemel sınıf olarak kullanılır. Django belgelerine göre:

ObjectDoesNotExist ve DoesNotExist

istisna DoesNotExist

DoesNotExist bir nesne bir sorgunun verilen parametreler için bulunan değilken özel durumu oluşturuldu. Django, bulunamayan nesne sınıfını tanımlamak ve / ile belirli bir model sınıfını yakalamanızı sağlamak için her model sınıfının bir özniteliği olarak bir DoesNotExist istisnası sağlar .tryexcept

Bunu yapan sihir budur. Model oluşturulduktan sonra, self.field.rel.to.DoesNotExistbu model için varolmayan istisna olur.


7
Çünkü hata DjangoRestFramework'daydı ve model bu noktada gelmek biraz zor. ObjectDoesNotExist yakalamak için yerleşti.
boatcoder

3
Belirli koşullar altında daha iyi bir seçenek olabilecek AttributeError öğesini de kullanabilirsiniz (bu hata, bir kaydın "özniteliğine" eriştiğinizde hemen hemen her zaman gerçekleşir, bu şekilde bu özniteliğin bir kayıt ya da değil.
Ürdün Reiter

1
Evet, tamam. Ama neden sadece Geri Dönemiyor? Özellikle bire bir alanlarla. Yoksa bunun iyi bir nedeni var mı?
Neil

61

İlgili model sınıfını içe aktarmak istemiyorsanız şunları yapabilirsiniz:

except MyModel.related_field.RelatedObjectDoesNotExist:

veya

except my_model_instance._meta.model.related_field.RelatedObjectDoesNotExist:

related_fieldalan adı nerede .


7
bu, dairesel ithalatlardan kaçınmanız gerektiğinde oldukça kullanışlıdır. Teşekkürler
Giovanni Di Milia

40

Bu istisnayı genel olarak yakalamak için şunları yapabilirsiniz:

from django.core.exceptions import ObjectDoesNotExist

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

2
Bu aslında beklendiği gibi hata yakalamak değildi bulundu. <Model>.DoesNotExistDid
Eric Blum

1
@EricBlum <Model> .DoesNotExist, ObjectDoesNotExist'in soyundan gelir, bu yüzden olmamalıdır. Neden olduğunu anlayabilir veya kodunuz hakkında daha fazla bilgi verebilir misiniz?
Zags

10

RelatedObjectDoesNotExistİstisna zamanında dinamik olarak oluşturulur. İşte ForwardManyToOneDescriptorve ReverseOneToOneDescriptortanımlayıcılar için ilgili kod snippet'i :

@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),
        {}
    )

Dan istisna INHERITS Yani <model name>.DoesNotExistve AttributeError. Aslında, bu istisna türü için tam MRO şöyledir:

[<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'>]

Temel paket, bağlamınızda en mantıklı olanı yakalayabilmeniz <model name>.DoesNotExist, ObjectDoesNotExist(içeri aktarabileceğiniz django.core.exceptions) veya alabileceğinizdir AttributeError.


2

tdelaney'in cevabı normal kod yolları için harikadır, ancak testlerde bu istisnayı nasıl yakalayacağınızı bilmeniz gerekiyorsa:

from django.core.exceptions import ObjectDoesNotExist

...

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

2

Biraz geç ama diğerleri için yararlı.

Bunu halletmenin 2 yolu.

1 inci :

İstisnayı yakalamamız gerektiğinde

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

2: İstisna işlemek istemediğinizde

>>> hasattr(p2, 'restaurant')
False
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.