#35438 closed Uncategorized (duplicate)
Failed to insert an model instance into db that utilizes a UUID as its primary key and incorporates a GeneratedField.
Reported by: | 长孙弘奕 | Owned by: | nobody |
---|---|---|---|
Component: | Uncategorized | Version: | 5.0 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I have defined a model that employs a UUIDField as its primary key, accompanied by a JSONField and several GeneratedFields, which are intended for indexing the JSONFields. However, when attempting to load data via loaddata from a JSON fixture, the process fails during the execution of the execute_sql method within django/db/models/SQL/compiler.py. The problematic code snippet is as follows:
def execute_sql(self, returning_fields=None): .... if not self.returning_fields: return [] .... else: cols = [opts.pk.get_col(opts.db_table)] rows = [ ( self.connection.ops.last_insert_id( cursor, opts.db_table, opts.pk.column, ), ) ] converters = self.get_converters(cols) if converters: rows = list(self.apply_converters(rows, converters)) return rows
Here, returning_fields comprises GeneratedFields, thereby preventing the method from directly returning an empty list at the outset of its logical execution. Moreover, since the model's primary key is not an AUTO_INCREMENT column (it's a UUID), last_insert_id() erroneously returns 0. This subsequently triggers an error within self.apply_converters(rows, converters) as it attempts to treat 0 as a UUID.
To address this issue, the else block logic requires adjustment to accommodate the presence of GeneratedField. Alternatively, within django/db/models/base.py's _save_table method, one could exclude GeneratedField from returning_fields. A modified approach might resemble:
#Original: returning_fields = meta.db_returning_fields returning_fields = [ f for f in meta.db_returning_fields if not f.generated] results = self._do_insert( cls._base_manager, using, fields, returning_fields, raw ) if results: for value, field in zip(results[0], returning_fields): setattr(self, field.attname, value) return updated
This adjusted strategy has proven effective in my project, successfully circumventing the aforementioned issues without introducing new problems.
Change History (2)
comment:1 by , 16 months ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
comment:2 by , 13 days ago
Resolution: | needsinfo → duplicate |
---|
Enough information to reproduce was eventually given in #36086.
Hi 长孙弘奕, thank you for the report and patch.
I'm struggling to see exactly what is happening here. Can you perhaps share your model, fixture and error?
If you provide a regression test to the patch that will also be really helpful to be able to see the issue