diff --git a/django/contrib/postgres/fields/array.py b/django/contrib/postgres/fields/array.py index 772ab9e586d..dea9c0440da 100644 --- a/django/contrib/postgres/fields/array.py +++ b/django/contrib/postgres/fields/array.py @@ -94,6 +94,14 @@ class ArrayField(Field): value = [self.base_field.to_python(val) for val in vals] return value + def get_default(self): + """Overridden from the default to prevent string-mangling.""" + if self.has_default(): + if callable(self.default): + return self.default() + return self.default + return '' + def value_to_string(self, obj): values = [] vals = self._get_val_from_obj(obj) diff --git a/tests/postgres_tests/array_default_migrations/0001_initial.py b/tests/postgres_tests/array_default_migrations/0001_initial.py new file mode 100644 index 00000000000..0b7eb77c3de --- /dev/null +++ b/tests/postgres_tests/array_default_migrations/0001_initial.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.contrib.postgres.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='CharArrayModel', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('field', django.contrib.postgres.fields.ArrayField(models.CharField(max_length=10), size=None)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='DateTimeArrayModel', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('field', django.contrib.postgres.fields.ArrayField(models.DateTimeField(), size=None)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='IntegerArrayModel', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('field', django.contrib.postgres.fields.ArrayField(models.IntegerField(), size=None)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='NestedIntegerArrayModel', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('field', django.contrib.postgres.fields.ArrayField(django.contrib.postgres.fields.ArrayField(models.IntegerField(), size=None), size=None)), + ], + options={ + }, + bases=(models.Model,), + ), + migrations.CreateModel( + name='NullableIntegerArrayModel', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('field', django.contrib.postgres.fields.ArrayField(models.IntegerField(), size=None, null=True, blank=True)), + ], + options={ + }, + bases=(models.Model,), + ), + ] diff --git a/tests/postgres_tests/array_default_migrations/0002_integerarraymodel_field_2.py b/tests/postgres_tests/array_default_migrations/0002_integerarraymodel_field_2.py new file mode 100644 index 00000000000..074c2f70e59 --- /dev/null +++ b/tests/postgres_tests/array_default_migrations/0002_integerarraymodel_field_2.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.contrib.postgres.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('postgres_tests', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='integerarraymodel', + name='field_2', + field=django.contrib.postgres.fields.ArrayField(models.IntegerField(), default=[], size=None), + preserve_default=False, + ), + ] diff --git a/tests/postgres_tests/array_default_migrations/__init__.py b/tests/postgres_tests/array_default_migrations/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/postgres_tests/test_array.py b/tests/postgres_tests/test_array.py index 1fc54defe78..33cf837dd47 100644 --- a/tests/postgres_tests/test_array.py +++ b/tests/postgres_tests/test_array.py @@ -4,10 +4,11 @@ import unittest from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.forms import SimpleArrayField, SplitArrayField from django.core import exceptions, serializers +from django.core.management import call_command from django.db import models, IntegrityError, connection from django.db.migrations.writer import MigrationWriter from django import forms -from django.test import TestCase +from django.test import TestCase, override_settings from django.utils import timezone from .models import IntegerArrayModel, NullableIntegerArrayModel, CharArrayModel, DateTimeArrayModel, NestedIntegerArrayModel @@ -226,6 +227,13 @@ class TestMigrations(TestCase): statement, imports = MigrationWriter.serialize(field) self.assertEqual(statement, 'django.contrib.postgres.fields.ArrayField(models.CharField(max_length=20), size=None)') + @override_settings(MIGRATION_MODULES={ + "postgres_tests": "postgres_tests.array_default_migrations", + }) + def test_adding_field_with_default(self): + # See #22962 + call_command('migrate', 'postgres_tests', verbosity=0) + @unittest.skipUnless(connection.vendor == 'postgresql', 'PostgreSQL required') class TestSerialization(TestCase):