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.
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.
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:
où related_field
est le nom du champ.
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
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.
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()