Este código está no django / db / models / fields.py Ele cria / define uma exceção?
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),
{}
)
Isso está no django / db / models / fields / related.py e gera a referida exceção acima:
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
O problema é que este código:
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
não vai pegar essa exceção
>>>print type(foo)
<class 'django.db.models.fields.related.RelatedObjectDoesNotExist'>
>>>isinstance(foo, related.FieldDoesNotExist)
False
e
except related.RelatedObjectDoesNotExist:
Gera um 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
e provavelmente é por isso.
related
?AttributeError
, em vez derelated.ReverseSingleRelatedObjectDescriptor.RelatedObjectDoesNotExist
Respostas:
Se o seu modelo relacionado for chamado Foo, você poderá:
Django é incrível quando não é aterrorizante.
RelatedObjectDoesNotExist
é uma propriedade que retorna um tipo que é descoberto dinamicamente no tempo de execução. Esse tipo usaself.field.rel.to.DoesNotExist
como uma classe base. De acordo com a documentação do Django:Essa é a mágica que faz isso acontecer. Depois que o modelo foi construído,
self.field.rel.to.DoesNotExist
a exceção não existe para esse modelo.fonte
Se você não deseja importar a classe de modelo relacionada, pode:
ou
onde
related_field
é o nome do campo.fonte
Para capturar essa exceção em geral, você pode fazer
fonte
<Model>.DoesNotExist
aconteceuA
RelatedObjectDoesNotExist
exceção é criada dinamicamente no tempo de execução. Aqui está o trecho de código relevante para os descritoresForwardManyToOneDescriptor
eReverseOneToOneDescriptor
:Portanto, a exceção herda de
<model name>.DoesNotExist
eAttributeError
. De fato, o MRO completo para esse tipo de exceção é:O takeaway básica é que você pode pegar
<model name>.DoesNotExist
,ObjectDoesNotExist
(importação dedjango.core.exceptions
) ouAttributeError
, o que faz mais sentido em seu contexto.fonte
A resposta de tdelaney é ótima para caminhos de código regulares, mas se você precisar saber como capturar essa exceção nos testes:
fonte
Um pouco tarde, mas útil para os outros.
2 maneiras de lidar com isso.
1º:
Quando precisamos pegar uma exceção
2º: quando não quiser lidar com exceção
fonte