diff options
| author | Chris Wesseling <chris@maykinmedia.nl> | 2025-11-20 15:01:14 +0100 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2025-11-20 17:24:10 -0500 |
| commit | ac9bdcabe10fb7ac0c7e9ebcd879f5e34bee776f (patch) | |
| tree | 517bd72a81b32a1e0664a0b9a22cdd2c56a67356 | |
| parent | 001c2f546b4053acb04f16d6b704f7b4fbca1c45 (diff) | |
[5.2.x] Fixed #36748 -- Filtered non-standard placeholders from UNNEST queries.
Backport of 5834643f43a767fe19f2c6d10217b204e7584ec8 from main.
| -rw-r--r-- | django/db/backends/postgresql/compiler.py | 5 | ||||
| -rw-r--r-- | docs/releases/5.2.9.txt | 3 | ||||
| -rw-r--r-- | tests/postgres_tests/fields.py | 5 | ||||
| -rw-r--r-- | tests/postgres_tests/migrations/0002_create_test_models.py | 23 | ||||
| -rw-r--r-- | tests/postgres_tests/models.py | 5 | ||||
| -rw-r--r-- | tests/postgres_tests/test_bulk_update.py | 8 |
6 files changed, 49 insertions, 0 deletions
diff --git a/django/db/backends/postgresql/compiler.py b/django/db/backends/postgresql/compiler.py index 344773fb7a..dc2db148ae 100644 --- a/django/db/backends/postgresql/compiler.py +++ b/django/db/backends/postgresql/compiler.py @@ -36,6 +36,11 @@ class SQLInsertCompiler(BaseSQLInsertCompiler): # Lack of fields denote the usage of the DEFAULT keyword # for the insertion of empty rows. or any(field is None for field in fields) + # Field.get_placeholder takes value as an argument, so the + # resulting placeholder might be dependent on the value. + # in UNNEST requires a single placeholder to "fit all values" in + # the array. + or any(hasattr(field, "get_placeholder") for field in fields) # Fields that don't use standard internal types might not be # unnest'able (e.g. array and geometry types are known to be # problematic). diff --git a/docs/releases/5.2.9.txt b/docs/releases/5.2.9.txt index 0d726de640..588c278be5 100644 --- a/docs/releases/5.2.9.txt +++ b/docs/releases/5.2.9.txt @@ -13,3 +13,6 @@ Bugfixes ``django.utils.feedgenerator.Stylesheet.__str__()`` did not escape the ``url``, ``mimetype``, and ``media`` attributes, potentially leading to invalid XML markup (:ticket:`36733`). + +* Fixed a bug in Django 5.2 on PostgreSQL where ``bulk_create()`` did not apply + a field's custom query placeholders (:ticket:`36748`). diff --git a/tests/postgres_tests/fields.py b/tests/postgres_tests/fields.py index c5dddf197f..d099effdd5 100644 --- a/tests/postgres_tests/fields.py +++ b/tests/postgres_tests/fields.py @@ -57,3 +57,8 @@ except ImportError: class EnumField(models.CharField): def get_prep_value(self, value): return value.value if isinstance(value, enum.Enum) else value + + +class OffByOneField(models.IntegerField): + def get_placeholder(self, value, compiler, connection): + return "(%s + 1)" diff --git a/tests/postgres_tests/migrations/0002_create_test_models.py b/tests/postgres_tests/migrations/0002_create_test_models.py index 31705ae21a..1aa900f07a 100644 --- a/tests/postgres_tests/migrations/0002_create_test_models.py +++ b/tests/postgres_tests/migrations/0002_create_test_models.py @@ -9,6 +9,7 @@ from ..fields import ( EnumField, HStoreField, IntegerRangeField, + OffByOneField, SearchVectorField, ) from ..models import TagField @@ -570,4 +571,26 @@ class Migration(migrations.Migration): "required_db_vendor": "postgresql", }, ), + migrations.CreateModel( + name="OffByOneModel", + fields=[ + ( + "id", + models.BigAutoField( + verbose_name="ID", + serialize=False, + auto_created=True, + primary_key=True, + ), + ), + ( + "one_off", + OffByOneField(), + ), + ], + options={ + "required_db_vendor": "postgresql", + }, + bases=(models.Model,), + ), ] diff --git a/tests/postgres_tests/models.py b/tests/postgres_tests/models.py index 1563f6a35d..7c606a83a9 100644 --- a/tests/postgres_tests/models.py +++ b/tests/postgres_tests/models.py @@ -9,6 +9,7 @@ from .fields import ( EnumField, HStoreField, IntegerRangeField, + OffByOneField, SearchVectorField, ) @@ -207,3 +208,7 @@ class HotelReservation(PostgreSQLModel): end = models.DateTimeField() cancelled = models.BooleanField(default=False) requirements = models.JSONField(blank=True, null=True) + + +class OffByOneModel(PostgreSQLModel): + one_off = OffByOneField() diff --git a/tests/postgres_tests/test_bulk_update.py b/tests/postgres_tests/test_bulk_update.py index 85dfcedd09..f3e8ac8a40 100644 --- a/tests/postgres_tests/test_bulk_update.py +++ b/tests/postgres_tests/test_bulk_update.py @@ -6,6 +6,7 @@ from .models import ( IntegerArrayModel, NestedIntegerArrayModel, NullableIntegerArrayModel, + OffByOneModel, OtherTypesArrayModel, RangesModel, ) @@ -44,3 +45,10 @@ class BulkSaveTests(PostgreSQLTestCase): self.assertSequenceEqual( Model.objects.filter(**{field: new}), instances ) + + def test_bulk_create(self): + OffByOneModel.objects.bulk_create(OffByOneModel(one_off=0) for _ in range(20)) + + self.assertSequenceEqual( + [m.one_off for m in OffByOneModel.objects.all()], 20 * [1] + ) |
