Làm thế nào để bạn bắt được ngoại lệ này?


161

Mã này có trong django / db / model / Field.py Nó tạo / định nghĩa một ngoại lệ?

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

Đây là trong django / db / mô hình / trường / có liên quan, nó làm tăng ngoại lệ nói trên:

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

Vấn đề là mã này:

    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

sẽ không bắt ngoại lệ đó

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

except related.RelatedObjectDoesNotExist:

Tăng một 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

đó có lẽ là lý do tại sao


Làm thế nào bạn đã nhập khẩu related?
John Zwinck

4
sử dụng AttributeErrorthay vìrelated.ReverseSingleRelatedObjectDescriptor.RelatedObjectDoesNotExist
cinda

Có @JohnZwinck Tôi đã nhập liên quan.
thuyền viên

Câu trả lời:


301

Nếu mô hình liên quan của bạn được gọi là Foo, bạn có thể thực hiện:

except Foo.DoesNotExist:

Django là tuyệt vời khi nó không đáng sợ. RelatedObjectDoesNotExistlà một thuộc tính trả về một kiểu được tìm ra động khi chạy. Loại đó sử dụng self.field.rel.to.DoesNotExistnhư một lớp cơ sở. Theo tài liệu của Django:

ObjectDoesNotExist và DoesNotExist

ngoại lệ DoesNotExist

Các DoesNotExist ngoại lệ xảy ra khi một đối tượng không được tìm thấy cho các thông số nhất định của một truy vấn. Django cung cấp ngoại lệ DoesNotExist như một thuộc tính của từng lớp mô hình để xác định lớp đối tượng không thể tìm thấy và cho phép bạn bắt một lớp mô hình cụ thể có try/except .

Đây là điều kỳ diệu làm cho điều đó xảy ra. Khi mô hình đã được xây dựng, self.field.rel.to.DoesNotExistlà ngoại lệ không tồn tại cho mô hình đó.


7
Bởi vì lỗi là ở DjangoRestFramework và mô hình hơi khó xuất hiện vào thời điểm đó. Tôi đã giải quyết để bắt ObjectDoesNotExist.
thuyền viên

3
Bạn cũng có thể sử dụng AttributionError, trong một số trường hợp nhất định có thể là một lựa chọn tốt hơn (lỗi này hầu như luôn xảy ra khi bạn truy cập vào "thuộc tính" của bản ghi, vì vậy theo cách này bạn không phải theo dõi xem thuộc tính này có tương ứng với ghi hay không.
Jordan Reiter

1
Yeaaaa được rồi. Nhưng tại sao nó không thể trở về Không? Đặc biệt là với các lĩnh vực một-một. Hoặc có một lý do tốt?
Neil

61

Nếu bạn không muốn nhập lớp mô hình liên quan, bạn có thể:

except MyModel.related_field.RelatedObjectDoesNotExist:

hoặc là

except my_model_instance._meta.model.related_field.RelatedObjectDoesNotExist:

nơi related_fieldlà tên trường.


7
Điều này thực sự khá hữu ích trong trường hợp bạn cần tránh nhập khẩu vòng tròn. Cảm ơn
Giovanni Di Milia

40

Để bắt ngoại lệ này nói chung, bạn có thể làm

from django.core.exceptions import ObjectDoesNotExist

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

2
Tôi thấy điều này không thực sự bắt lỗi như mong đợi. Việc <Model>.DoesNotExistđã làm
Eric Blum

1
@EricBlum <Model> .DoesNotExist là hậu duệ của ObjectDoesNotExist, vì vậy điều đó không nên xảy ra. Bạn có thể tìm hiểu lý do tại sao nó đang xảy ra hoặc cung cấp thêm chi tiết về mã của bạn?
Zags

10

Các RelatedObjectDoesNotExistngoại lệ được tạo ra tự động khi chạy. Dưới đây là đoạn mã có liên quan cho ForwardManyToOneDescriptorReverseOneToOneDescriptormô tả:

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

Vì vậy, ngoại lệ kế thừa từ <model name>.DoesNotExistAttributeError. Trên thực tế, MRO hoàn chỉnh cho loại ngoại lệ này là:

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

Các takeaway cơ bản là bạn có thể nắm bắt <model name>.DoesNotExist, ObjectDoesNotExist(nhập từ django.core.exceptions) hoặc AttributeError, bất cứ điều gì có ý nghĩa nhất trong bối cảnh của bạn.


2

Câu trả lời của tdelaney là tuyệt vời cho các đường dẫn mã thông thường, nhưng nếu bạn cần biết cách bắt ngoại lệ này trong các bài kiểm tra:

from django.core.exceptions import ObjectDoesNotExist

...

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

2

Một chút muộn màng nhưng hữu ích cho người khác.

2 cách để xử lý việc này.

Ngày 1

Khi chúng ta cần bắt ngoại lệ

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

Lần 2: Khi không muốn xử lý ngoại lệ

>>> hasattr(p2, 'restaurant')
False
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.