mirror of https://github.com/django/django.git
Fixed #35024 -- Fixed model instance creation crash on GeneratedField.output_field with backend converters.
Regression in d9de74141e
.
This is a long standing issue, however it caused a crash of
GeneratedFields for all output fields that have backend-specific
converters when the RETURNING clause is not supported
(MySQL and SQLite < 3.35).
That's why severity was exacerbated.
This commit is contained in:
parent
2dca98f4f7
commit
5b3b791e90
|
@ -1819,6 +1819,7 @@ class SQLInsertCompiler(SQLCompiler):
|
||||||
)
|
)
|
||||||
opts = self.query.get_meta()
|
opts = self.query.get_meta()
|
||||||
self.returning_fields = returning_fields
|
self.returning_fields = returning_fields
|
||||||
|
cols = []
|
||||||
with self.connection.cursor() as cursor:
|
with self.connection.cursor() as cursor:
|
||||||
for sql, params in self.as_sql():
|
for sql, params in self.as_sql():
|
||||||
cursor.execute(sql, params)
|
cursor.execute(sql, params)
|
||||||
|
@ -1829,6 +1830,7 @@ class SQLInsertCompiler(SQLCompiler):
|
||||||
and len(self.query.objs) > 1
|
and len(self.query.objs) > 1
|
||||||
):
|
):
|
||||||
rows = self.connection.ops.fetch_returned_insert_rows(cursor)
|
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:
|
elif self.connection.features.can_return_columns_from_insert:
|
||||||
assert len(self.query.objs) == 1
|
assert len(self.query.objs) == 1
|
||||||
rows = [
|
rows = [
|
||||||
|
@ -1837,7 +1839,9 @@ class SQLInsertCompiler(SQLCompiler):
|
||||||
self.returning_params,
|
self.returning_params,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
cols = [field.get_col(opts.db_table) for field in self.returning_fields]
|
||||||
else:
|
else:
|
||||||
|
cols = [opts.pk.get_col(opts.db_table)]
|
||||||
rows = [
|
rows = [
|
||||||
(
|
(
|
||||||
self.connection.ops.last_insert_id(
|
self.connection.ops.last_insert_id(
|
||||||
|
@ -1847,7 +1851,6 @@ class SQLInsertCompiler(SQLCompiler):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
cols = [field.get_col(opts.db_table) for field in self.returning_fields]
|
|
||||||
converters = self.get_converters(cols)
|
converters = self.get_converters(cols)
|
||||||
if converters:
|
if converters:
|
||||||
rows = list(self.apply_converters(rows, converters))
|
rows = list(self.apply_converters(rows, converters))
|
||||||
|
|
|
@ -12,3 +12,7 @@ Bugfixes
|
||||||
* Reallowed, following a regression in Django 5.0, using a foreign key to a
|
* Reallowed, following a regression in Django 5.0, using a foreign key to a
|
||||||
model with a primary key that is not ``AutoField`` in
|
model with a primary key that is not ``AutoField`` in
|
||||||
:attr:`.ModelAdmin.list_filter` (:ticket:`35020`).
|
: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`).
|
||||||
|
|
|
@ -482,6 +482,18 @@ class UUIDGrandchild(UUIDChild):
|
||||||
pass
|
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):
|
class GeneratedModel(models.Model):
|
||||||
a = models.IntegerField()
|
a = models.IntegerField()
|
||||||
b = models.IntegerField()
|
b = models.IntegerField()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import uuid
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.db import IntegrityError, connection
|
from django.db import IntegrityError, connection
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
|
@ -14,6 +16,7 @@ from django.test.utils import isolate_apps
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
GeneratedModel,
|
GeneratedModel,
|
||||||
|
GeneratedModelFieldWithConverters,
|
||||||
GeneratedModelNull,
|
GeneratedModelNull,
|
||||||
GeneratedModelNullVirtual,
|
GeneratedModelNullVirtual,
|
||||||
GeneratedModelOutputFieldDbCollation,
|
GeneratedModelOutputFieldDbCollation,
|
||||||
|
@ -266,6 +269,11 @@ class StoredGeneratedFieldTests(GeneratedFieldTestMixin, TestCase):
|
||||||
output_field_db_collation_model = GeneratedModelOutputFieldDbCollation
|
output_field_db_collation_model = GeneratedModelOutputFieldDbCollation
|
||||||
params_model = GeneratedModelParams
|
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")
|
@skipUnlessDBFeature("supports_virtual_generated_columns")
|
||||||
class VirtualGeneratedFieldTests(GeneratedFieldTestMixin, TestCase):
|
class VirtualGeneratedFieldTests(GeneratedFieldTestMixin, TestCase):
|
||||||
|
|
Loading…
Reference in New Issue