web-dev-qa-db-fra.com

Comment attrapez-vous cette exception?

Ce code est dans Django/db/models/fields.py Il crée/définit une exception?

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

C’est dans Django/db/models/fields/related.py que cette exception est soulevée ci-dessus:

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

Le problème est que ce code:

    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

ne pas attraper cette exception

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

et

except related.RelatedObjectDoesNotExist:

Lève un 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

ce qui est probablement pourquoi.

140
boatcoder

Si votre modèle associé s'appelle Foo, vous pouvez simplement faire:

except Foo.DoesNotExist:

Django est incroyable quand ce n'est pas terrifiant. RelatedObjectDoesNotExist est une propriété qui renvoie un type déterminé dynamiquement à l'exécution. Ce type utilise self.field.rel.to.DoesNotExist en tant que classe de base. Selon Django documentation:

ObjectDoesNotExist et DoesNotExist

exception DoesNotExist

L'exception DoesNotExist est déclenchée lorsqu'un objet n'est pas trouvé pour les paramètres donnés d'une requête. Django fournit une exception DoesNotExist en tant qu'attribut de chaque classe de modèle pour identifier la classe d'objet introuvable et vous permettre d'attraper un modèle particulier. classe avec try/except.

C'est la magie qui rend cela possible. Une fois le modèle créé, self.field.rel.to.DoesNotExist est l'exception à ne pas exister pour ce modèle.

267
tdelaney

Si vous ne souhaitez pas importer la classe de modèle associée, vous pouvez:

except MyModel.related_field.RelatedObjectDoesNotExist:

ou

except my_model_instance._meta.model.related_field.RelatedObjectDoesNotExist:

related_field est le nom du champ.

47
Fush

Pour attraper cette exception en général, vous pouvez faire

from Django.core.exceptions import ObjectDoesNotExist

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

L'exception RelatedObjectDoesNotExist est créée dynamiquement à l'exécution. Voici l'extrait de code pertinent pour les descripteurs ForwardManyToOneDescriptor et ReverseOneToOneDescriptor:

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

Ainsi, l’exception hérite de <model name>.DoesNotExist et AttributeError. En fait, le MRO complet pour ce type d'exception est:

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

La livraison de base est que vous pouvez attraper <model name>.DoesNotExist, ObjectDoesNotExist (importer de Django.core.exceptions) ou AttributeError, selon ce qui vous semble le plus logique dans votre contexte.

8
C S

la réponse de tdelaney est excellente pour les chemins de code normaux, mais si vous avez besoin de savoir comment intercepter cette exception lors des tests:

from Django.core.exceptions import ObjectDoesNotExist

...

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