[Django] #34918: Assigning model instance to `_id`/attname field saves correctly, but breaks accessing the field

4 views
Skip to first unread message

Django

unread,
Oct 20, 2023, 9:58:58 AM10/20/23
to django-...@googlegroups.com
#34918: Assigning model instance to `_id`/attname field saves correctly, but breaks
accessing the field
-------------------------------------+-------------------------------------
Reporter: ricardo- | Owner: nobody
passthrough |
Type: Bug | Status: new
Component: Database | Version: 4.2
layer (models, ORM) |
Severity: Normal | Keywords:
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
Model definition:

{{{#!python
class Author(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4,
editable=False)

class Book(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4,
editable=False)
author = models.ForeignKey(
Author, null=True, blank=True, on_delete=models.CASCADE
)
}}}

{{{#!python
In [1]: book = Book.objects.create()

In [2]: author = Author.objects.create()

In [3]: book.author_id

In [4]: book.author

In [5]: book.author_id = author

In [6]: book.save()

In [7]: book.author
---------------------------------------------------------------------------
KeyError Traceback (most recent call
last)
...
ValidationError: ['“Author object (caaf8f9a-f934-44e9-8e6b-00d71d116acf)”
is not a valid UUID.']
}}}

Similarly, if someone tries to use `book.author_id` to fetch an author
using `Author.objects.get(id=book.author_id)` will also fail with a
similar error.

--
Ticket URL: <https://code.djangoproject.com/ticket/34918>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Oct 21, 2023, 12:21:03 AM10/21/23
to django-...@googlegroups.com
#34918: Assigning model instance to `_id`/attname field saves correctly, but breaks
accessing the field
-------------------------------------+-------------------------------------
Reporter: Ricardo Busquet | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Rahul Beniwal):

Hi Ricardo Busquet

I checked this, and you are right. But instead of assigning
`book.author_id=author` to `book.author=author` it seems to be working
fine.


{{{#!python
In [23]: book.author = author

In [24]: book.save()

In [25]: book.author_id
Out[25]: UUID('857acf04-960a-40ae-9c85-8c363b0a0dfd')

In [26]: book.author
Out[26]: <Author: Author object (857acf04-960a-40ae-9c85-8c363b0a0dfd)>

In [27]: Author.objects.get(id=book.author_id)
Out[27]: <Author: Author object (857acf04-960a-40ae-9c85-8c363b0a0dfd)>
}}}

Can we update the documentation for the UUID field to aware reader about
this situation or code level changes are needed?

Please feel free to assign this to me

--
Ticket URL: <https://code.djangoproject.com/ticket/34918#comment:1>

Django

unread,
Oct 21, 2023, 5:30:41 PM10/21/23
to django-...@googlegroups.com
#34918: Assigning model instance to `_id`/attname field saves correctly, but breaks
accessing the field
-------------------------------------+-------------------------------------
Reporter: Ricardo Busquet | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Tim Graham):

Django generally doesn't validate model attribute assignments. For
example, if Book has a title `CharField`, you can assign it the wrong
type, like `datetime` and it'll be silently coerced to string. I don't
think we're going to add this sort of validation or document it, but I
will leave this ticket open for a second opinion in case I'm overlooking
something.

Incidentally, similar steps with `id` as an `AutoField` also save
correctly but subsequently fail on access:
{{{ #!python
Traceback (most recent call last):
File
"/home/tim/code/django/django/db/models/fields/related_descriptors.py",
line 235, in __get__
rel_obj = self.field.get_cached_value(instance)
File "/home/tim/code/django/django/db/models/fields/mixins.py", line 15,
in get_cached_value
return instance._state.fields_cache[cache_name]
KeyError: 'reporter'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/tim/code/django/django/db/models/fields/__init__.py", line
2116, in get_prep_value
return int(value)
TypeError: int() argument must be a string, a bytes-like object or a real
number, not 'Reporter'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/home/tim/code/django/tests/many_to_one/tests.py", line 856, in
test_cached_relation_invalidated_on_save
self.assertEqual(self.a.reporter, self.r2)
File
"/home/tim/code/django/django/db/models/fields/related_descriptors.py",
line 253, in __get__
rel_obj = self.get_object(instance)
File
"/home/tim/code/django/django/db/models/fields/related_descriptors.py",
line 216, in get_object
return qs.get(self.field.get_reverse_related_filter(instance))
File "/home/tim/code/django/django/db/models/query.py", line 633, in get
clone = self._chain() if self.query.combinator else self.filter(*args,
**kwargs)
File "/home/tim/code/django/django/db/models/query.py", line 1476, in
filter
return self._filter_or_exclude(False, args, kwargs)
File "/home/tim/code/django/django/db/models/query.py", line 1494, in
_filter_or_exclude
clone._filter_or_exclude_inplace(negate, args, kwargs)
File "/home/tim/code/django/django/db/models/query.py", line 1501, in
_filter_or_exclude_inplace
self._query.add_q(Q(*args, **kwargs))
File "/home/tim/code/django/django/db/models/sql/query.py", line 1599,
in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
File "/home/tim/code/django/django/db/models/sql/query.py", line 1631,
in _add_q
child_clause, needed_inner = self.build_filter(
File "/home/tim/code/django/django/db/models/sql/query.py", line 1458,
in build_filter
return self._add_q(
File "/home/tim/code/django/django/db/models/sql/query.py", line 1631,
in _add_q
child_clause, needed_inner = self.build_filter(
File "/home/tim/code/django/django/db/models/sql/query.py", line 1545,
in build_filter
condition = self.build_lookup(lookups, col, value)
File "/home/tim/code/django/django/db/models/sql/query.py", line 1375,
in build_lookup
lookup = lookup_class(lhs, rhs)
File "/home/tim/code/django/django/db/models/lookups.py", line 30, in
__init__
self.rhs = self.get_prep_lookup()
File "/home/tim/code/django/django/db/models/lookups.py", line 362, in
get_prep_lookup
return super().get_prep_lookup()
File "/home/tim/code/django/django/db/models/lookups.py", line 88, in
get_prep_lookup
return self.lhs.output_field.get_prep_value(self.rhs)
File "/home/tim/code/django/django/db/models/fields/__init__.py", line
2118, in get_prep_value
raise e.__class__(
TypeError: Field 'id' expected a number but got <Reporter: Paul Jones>.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/34918#comment:2>

Django

unread,
Oct 22, 2023, 4:56:16 AM10/22/23
to django-...@googlegroups.com
#34918: Assigning model instance to `_id`/attname field saves correctly, but breaks
accessing the field
-------------------------------------+-------------------------------------
Reporter: Ricardo Busquet | Owner: nobody
Type: Bug | Status: closed

Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution: invalid

Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* status: new => closed
* resolution: => invalid


Comment:

I agree with Tim.

--
Ticket URL: <https://code.djangoproject.com/ticket/34918#comment:3>

Reply all
Reply to author
Forward
0 new messages