mirror of
https://github.com/django/django.git
synced 2025-03-06 15:32:33 +00:00
[5.2.x] Fixed #36107 -- Adjusted UNNEST bulk_create strategy to opt-out sized arrays.
The array fields opt-out heuristic failed to account for sized arrays. Note that we keep relying on db_type as opposed to performing an ArrayField instance check against the column's field as there could be other implementations of model fields that use Postgres arrays to store the optimization must be disabled for all of them. Refs #35936. Thanks Claude Paroz for the report and test. Backport of 22fc151bb86a553d84c62d7effd289356e9b6c6c from main.
This commit is contained in:
parent
dab04b89af
commit
ad6bca92a8
@ -43,7 +43,7 @@ class SQLInsertCompiler(BaseSQLInsertCompiler):
|
||||
db_types = [field.db_type(self.connection) for field in fields]
|
||||
# Abort if any of the fields are arrays as UNNEST indiscriminately
|
||||
# flatten them instead of reducing their nesting by one.
|
||||
if any(db_type.endswith("[]") for db_type in db_types):
|
||||
if any(db_type.endswith("]") for db_type in db_types):
|
||||
return super().assemble_as_sql(fields, value_rows)
|
||||
return InsertUnnest(["(%%s)::%s[]" % db_type for db_type in db_types]), [
|
||||
list(map(list, zip(*value_rows)))
|
||||
|
@ -167,6 +167,28 @@ class Migration(migrations.Migration):
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="WithSizeArrayModel",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
verbose_name="ID",
|
||||
serialize=False,
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"field",
|
||||
ArrayField(models.FloatField(), size=2, null=True, blank=True),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"required_db_vendor": "postgresql",
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="NullableIntegerArrayModel",
|
||||
fields=[
|
||||
|
@ -64,6 +64,10 @@ class DateTimeArrayModel(PostgreSQLModel):
|
||||
times = ArrayField(models.TimeField())
|
||||
|
||||
|
||||
class WithSizeArrayModel(PostgreSQLModel):
|
||||
field = ArrayField(models.FloatField(), size=3)
|
||||
|
||||
|
||||
class NestedIntegerArrayModel(PostgreSQLModel):
|
||||
field = ArrayField(ArrayField(models.IntegerField()))
|
||||
|
||||
|
@ -28,6 +28,7 @@ from .models import (
|
||||
OtherTypesArrayModel,
|
||||
PostgreSQLModel,
|
||||
Tag,
|
||||
WithSizeArrayModel,
|
||||
)
|
||||
|
||||
try:
|
||||
@ -216,6 +217,16 @@ class TestQuerying(PostgreSQLTestCase):
|
||||
]
|
||||
)
|
||||
|
||||
def test_bulk_create_with_sized_arrayfield(self):
|
||||
objs = WithSizeArrayModel.objects.bulk_create(
|
||||
[
|
||||
WithSizeArrayModel(field=[1, 2]),
|
||||
WithSizeArrayModel(field=[3, 4]),
|
||||
]
|
||||
)
|
||||
self.assertEqual(objs[0].field, [1, 2])
|
||||
self.assertEqual(objs[1].field, [3, 4])
|
||||
|
||||
def test_empty_list(self):
|
||||
NullableIntegerArrayModel.objects.create(field=[])
|
||||
obj = (
|
||||
|
Loading…
x
Reference in New Issue
Block a user