#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 , 18 months ago
| Resolution: | → needsinfo |
|---|---|
| Status: | new → closed |
comment:2 by , 3 months 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