#30309: Remove hasattr reference in One-to-One documentation example
-------------------------------+--------------------------------------
Reporter: David Beitey | Owner: nobody
Type: Uncategorized | Status: closed
Component: Documentation | Version: 2.2
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage: Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Comment (by David Beitey):
Replying to [comment:3 felixxm]:
> `hasattr()` is not throwing an exceptions, just in case I checked with
Python 3.6/3.7 and Django 2.1/2.2.
>
> Did you check this?
>
> FYI: `RelatedObjectDoesNotExist` is a subclass of `AttributeError`.
Okay, I dug into the situation and what's happening isn't related to
Python version.
`RelatedObjectDoesNotExist` gets raised when the value of a OneToOneField
is None/null. However, if there is data in the field but it isn't present
in the related table, `[model_identifier].DoesNotExist` gets raised. The
latter exception doesn't inherit from `AttributeError` and isn't swallowed
with `hasattr()`.
Since the behaviour of `hasattr()` is to return False when there's no
related object, that seems to be what should happen in both situations --
with None as a value or a field value pointing at a non-existant related
object. In other words, it feels as though `RelatedObjectDoesNotExist`
should be being raised when accessing the attribute on the model in this
way, rather than at the query level (see traceback below).
Here's my example:
{{{
from django.db import models
class Person(models.Model):
login = models.CharField(db_column='login', max_length=100)
# and more...
class Meta:
managed = False
db_table = 'SYS_PEOPLE'
class Author(models.Model):
person = models.OneToOneField(Person,
db_column='login',
primary_key=True,
on_delete=models.CASCADE)
# and more...
class Meta:
managed = False
db_table = 'SYS_AUTHORS'
# manage.py shell
from app.models import Author
author = Author(person_id='fake')
author.person # raises DoesNotExist
hasattr(author, 'person') # raises DoesNotExist
author = Author(person_id=None)
author.person # raises RelatedObjectDoesNotExist
hasattr(author, 'person') # Swallows
}}}
Tracebacks:
{{{
Traceback (most recent call last):
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/db/models/fields/related_descriptors.py", line 163, in
__get__
rel_obj = self.field.get_cached_value(instance)
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/db/models/fields/mixins.py", line 13, in get_cached_value
return instance._state.fields_cache[cache_name]
KeyError: 'person'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./manage.py", line 17, in <module>
execute_from_command_line(sys.argv)
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/core/management/__init__.py", line 381, in
execute_from_command_line
utility.execute()
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/core/management/__init__.py", line 375, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/core/management/base.py", line 316, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/core/management/base.py", line 353, in execute
output = self.handle(*args, **options)
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/core/management/commands/shell.py", line 92, in handle
exec(sys.stdin.read())
File "<string>", line 4, in <module>
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/db/models/fields/related_descriptors.py", line 177, in
__get__
rel_obj = self.get_object(instance)
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/db/models/fields/related_descriptors.py", line 297, in
get_object
return super().get_object(instance)
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/db/models/fields/related_descriptors.py", line 144, in
get_object
return qs.get(self.field.get_reverse_related_filter(instance))
File "/home/user/local/share/virtualenvs/app-1933afW/lib/python3.7/site-
packages/django/db/models/query.py", line 399, in get
self.model._meta.object_name
app.models.person.DoesNotExist: Person matching query does not exist.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30309#comment:4>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/065.c50253eda26231a1692ac09fa93f8482%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.