diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 7cec040ceeed..cb559308cd0d 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -1819,6 +1819,7 @@ def execute_sql(self, returning_fields=None): ) opts = self.query.get_meta() self.returning_fields = returning_fields + cols = [] with self.connection.cursor() as cursor: for sql, params in self.as_sql(): cursor.execute(sql, params) @@ -1829,6 +1830,7 @@ def execute_sql(self, returning_fields=None): and len(self.query.objs) > 1 ): rows = self.connection.ops.fetch_returned_insert_rows(cursor) + cols = [field.get_col(opts.db_table) for field in self.returning_fields] elif self.connection.features.can_return_columns_from_insert: assert len(self.query.objs) == 1 rows = [ @@ -1837,7 +1839,9 @@ def execute_sql(self, returning_fields=None): self.returning_params, ) ] + cols = [field.get_col(opts.db_table) for field in self.returning_fields] else: + cols = [opts.pk.get_col(opts.db_table)] rows = [ ( self.connection.ops.last_insert_id( @@ -1847,7 +1851,6 @@ def execute_sql(self, returning_fields=None): ), ) ] - cols = [field.get_col(opts.db_table) for field in self.returning_fields] converters = self.get_converters(cols) if converters: rows = list(self.apply_converters(rows, converters)) diff --git a/docs/releases/5.0.1.txt b/docs/releases/5.0.1.txt index 871f55ec6d64..a8b886c6e2f4 100644 --- a/docs/releases/5.0.1.txt +++ b/docs/releases/5.0.1.txt @@ -12,3 +12,7 @@ Bugfixes * Reallowed, following a regression in Django 5.0, using a foreign key to a model with a primary key that is not ``AutoField`` in :attr:`.ModelAdmin.list_filter` (:ticket:`35020`). + +* Fixed a long standing bug in handling the ``RETURNING INTO`` clause that + caused a crash when creating a model instance with a ``GeneratedField`` which + ``output_field`` had backend-specific converters (:ticket:`35024`). diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py index b4b7b5bd4c5f..aea02964e2d1 100644 --- a/tests/model_fields/models.py +++ b/tests/model_fields/models.py @@ -482,6 +482,18 @@ class UUIDGrandchild(UUIDChild): pass +class GeneratedModelFieldWithConverters(models.Model): + field = models.UUIDField() + field_copy = models.GeneratedField( + expression=F("field"), + output_field=models.UUIDField(), + db_persist=True, + ) + + class Meta: + required_db_features = {"supports_stored_generated_columns"} + + class GeneratedModel(models.Model): a = models.IntegerField() b = models.IntegerField() diff --git a/tests/model_fields/test_generatedfield.py b/tests/model_fields/test_generatedfield.py index 9e5d9d87c361..056a80c29430 100644 --- a/tests/model_fields/test_generatedfield.py +++ b/tests/model_fields/test_generatedfield.py @@ -1,3 +1,5 @@ +import uuid + from django.apps import apps from django.db import IntegrityError, connection from django.db.models import ( @@ -14,6 +16,7 @@ from .models import ( GeneratedModel, + GeneratedModelFieldWithConverters, GeneratedModelNull, GeneratedModelNullVirtual, GeneratedModelOutputFieldDbCollation, @@ -266,6 +269,11 @@ class StoredGeneratedFieldTests(GeneratedFieldTestMixin, TestCase): output_field_db_collation_model = GeneratedModelOutputFieldDbCollation params_model = GeneratedModelParams + def test_create_field_with_db_converters(self): + obj = GeneratedModelFieldWithConverters.objects.create(field=uuid.uuid4()) + obj = self._refresh_if_needed(obj) + self.assertEqual(obj.field, obj.field_copy) + @skipUnlessDBFeature("supports_virtual_generated_columns") class VirtualGeneratedFieldTests(GeneratedFieldTestMixin, TestCase):