#24611: Manager update with object instance having UUID as PK fails
----------------------------------------------+--------------------
Reporter: jwineinger | Owner: nobody
Type: Uncategorized | Status: new
Component: Database layer (models, ORM) | Version: master
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
----------------------------------------------+--------------------
I'm using UUIDs for the primary keys of some models. Other models relate
to those via FK. I ran into an issue today when trying to do a
RelatedModel.objects.update(fk=instance_with_uuid_pk), where SQLite failed
with
{{{
Traceback (most recent call last):
File "/src/django/tests/update/tests.py", line 154, in
test_update_uuid_fk_with_model_instance
UUIDRelation.objects.update(relation=self.u1)
File "/src/django/django/db/models/manager.py", line 127, in
manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/src/django/django/db/models/query.py", line 619, in update
rows = query.get_compiler(self.db).execute_sql(CURSOR)
File "/src/django/django/db/models/sql/compiler.py", line 1056, in
execute_sql
cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
File "/src/django/django/db/models/sql/compiler.py", line 835, in
execute_sql
cursor.execute(sql, params)
File "/src/django/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/src/django/django/db/utils.py", line 95, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/src/django/django/utils/six.py", line 658, in reraise
raise value.with_traceback(tb)
File "/src/django/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/src/django/django/db/backends/sqlite3/base.py", line 318, in
execute
return Database.Cursor.execute(self, query, params)
django.db.utils.InterfaceError: Error binding parameter 0 - probably
unsupported type.
}}}
Examining the SQLite table showed a CHAR32 column for the UUID and FK
fields, which seems appropriate since SQLite doesn't have a UUID column
like postgres. Then I traced execution of the query and found that the
params being sent to SQLite was still a UUID, not the hex representation.
Inserting the primary models and related models works fine, so it seems to
be an issue with updates. It looks like the SQLUpdateCompiler calls
[https://github.com/django/django/blob/dc27f3ee0c3eb9bb17d6cb764788eeaf73a371d7/django/db/models/sql/compiler.py#L1015
prepare_database_save(field)] when a model instance is give as the query
value. That
[https://github.com/django/django/blob/dc27f3ee0c3eb9bb17d6cb764788eeaf73a371d7/django/db/models/base.py#L881
just returns the value of the related field], which is just a UUID in this
case. This is passed along for execution, where SQLite pukes.
However, if you pass a UUID as the value (not a model instance),
field.get_db_prep_save is called which will convert the UUID to its hex
value if the DB doesn't support native UUIDs. Thus, updates given a raw
UUID work fine.
So it seems like all that needs to change is that we need to call
field.get_db_prep_save on the value returned from
val.prepare_database_save. I've attached a patch that does this.
--
Ticket URL: <https://code.djangoproject.com/ticket/24611>
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/053.6b524cf9e34e9ba58d38117d40cf18af%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.