คุณจับข้อยกเว้นนี้ได้อย่างไร


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:

Django นั้นยอดเยี่ยมเมื่อมันไม่น่ากลัว RelatedObjectDoesNotExistเป็นคุณสมบัติที่ส่งคืนชนิดที่คิดออกแบบไดนามิกที่รันไทม์ ประเภทนั้นใช้self.field.rel.to.DoesNotExistเป็นคลาสพื้นฐาน ตามเอกสารของ Django:

ObjectDoesNotExist และ DoesNotExist

ยกเว้นDoesNotExist

กระบวนการDoesNotExistมีการยกข้อยกเว้นเมื่อไม่พบวัตถุสำหรับพารามิเตอร์ที่กำหนดของแบบสอบถาม Django ให้DoesNotExist ยกเว้นเป็นแอตทริบิวต์ของแต่ละชั้นเรียนรุ่นเพื่อระบุระดับของวัตถุที่ไม่สามารถพบได้และเพื่อให้คุณสามารถจับระดับรูปแบบเฉพาะที่มี/tryexcept

นี่คือเวทมนตร์ที่ทำให้เกิดขึ้น เมื่อสร้างแบบจำลองขึ้นแล้วself.field.rel.to.DoesNotExistจะมีข้อยกเว้นแบบไม่มีอยู่สำหรับโมเดลนั้น


7
เนื่องจากข้อผิดพลาดอยู่ใน DjangoRestFramework และโมเดลค่อนข้างยากที่จะมาในตอนนั้น ฉันตัดสินให้จับ ObjectDoesNotExist
boatcoder

3
นอกจากนี้คุณยังสามารถใช้ AttributeError ซึ่งภายใต้สถานการณ์บางอย่างอาจเป็นตัวเลือกที่ดีกว่า (ข้อผิดพลาดนี้มักเกิดขึ้นเมื่อคุณเข้าถึง "attribute" ของบันทึกดังนั้นวิธีนี้คุณไม่จำเป็นต้องติดตามว่าคุณลักษณะนี้สอดคล้องกับ บันทึกหรือไม่
Jordan Reiter

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
ฉันพบว่าสิ่งนี้ไม่ได้จับข้อผิดพลาดตามที่คาดไว้ The <Model>.DoesNotExistdid
Eric Blum

1
@EricBlum <Model> .DoesNotExist เป็นผู้สืบทอดของ ObjectDoesNotExist ดังนั้นไม่ควรเกิดขึ้น คุณสามารถขุดหาสาเหตุที่เกิดขึ้นหรือให้รายละเอียดเพิ่มเติมเกี่ยวกับรหัสของคุณได้หรือไม่?
Zags

10

RelatedObjectDoesNotExistยกเว้นจะสร้างแบบไดนามิกที่รันไทม์ นี่คือข้อมูลโค้ดที่เกี่ยวข้องสำหรับForwardManyToOneDescriptorและReverseOneToOneDescriptordescriptors:

@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

สายไปหน่อย แต่ก็มีประโยชน์สำหรับคนอื่น ๆ

2 วิธีในการจัดการกับสิ่งนี้

วันที่ 1:

เมื่อเราจำเป็นต้องจับข้อยกเว้น

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

2nd: เมื่อไม่ต้องการจัดการข้อยกเว้น

>>> hasattr(p2, 'restaurant')
False
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.