Opened 5 months ago
Closed 5 months ago
#35438 closed Uncategorized (needsinfo)
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.
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