Proposal: make ForwardManyToOneDescriptor.get_object raise self.RelatedObjectDoesNotExist

633 views
Skip to first unread message

David Beitey

unread,
Apr 16, 2019, 7:22:52 AM4/16/19
to Django developers (Contributions to Django itself)
This continues the discussion from https://code.djangoproject.com/ticket/30309.  That issue was a misreporting of the core issue which became apparent after further investigation; apologies for the noise, I am new to Django.

When a Django model is created with a OneToOneField, or created with a ForeignKey with:

    on_delete=models.DO_NOTHING, db_constraint=False

If the related model does not exist in the database (eg the remote object was removed or does not currently exist), attempting to access a relationship on an object will raise a DoesNotExist exception rather than a RelatedObjectDoesNotExist exception which is raised if the local field is empty.    An example traceback looks like this (full traceback at the end of this comment):

  [...]
File "django/db/models/fields/related_descriptors.py", line 177, in __get__ rel_obj = self.get_object(instance) File "django/db/models/fields/related_descriptors.py", line 297, in get_object return super().get_object(instance) File "django/db/models/fields/related_descriptors.py", line 144, in get_object return qs.get(self.field.get_reverse_related_filter(instance)) File "django/db/models/query.py", line 399, in get self.model._meta.object_name app.models.person.DoesNotExist: Person matching query does not exist.

By comparison, if the local field's value is empty (eg None/NULL, no relationship set), then a  RelatedObjectDoesNotExist exception will be raised
instead when attempting to access the relationship. This has the effect of impacting the
use of hasattr() if following the one-to-one relationships example
for
avoiding exception handling. In this case,
DoesNotExist doesn't inherit from AttributeError, so it isn't swallowed with hasattr()
but
RelatedObjectDoesNotExist does so it gets swallowed.

In short, it would be more consistent if accessing a non-existent related object raised RelatedObjectDoesNotExistFrom Simon Charette's comment on the original issue:

I'd be in favor of making ForwardManyToOneDescriptor.get_object raise self.RelatedObjectDoesNotExist as the current code clearly doesn't take db_constraint=False into account based on the heuristic comment there.


For context, parts of my database are managed outside of Django and retain records of remote object references as the data may return at some point (eg a limited view of HR database where staff may or may not have a record at a given point in time).  The local side of the relationship continues to have a value in case the remote object reappears (eg staff member is now employed) so in my context, both a value of NULL or a non-existent foreign key are conceptually the same, meaning there's no person object present.

Regards,
David


charettes

unread,
Apr 16, 2019, 10:09:35 AM4/16/19
to Django developers (Contributions to Django itself)
As I've said on the ticket I think we should make this change as
it's backward compatible and more coherent with the other
RelatedObjectDoesNotExist usages of the related fields API.

Cheers,
Simon
Reply all
Reply to author
Forward
0 new messages