Fixed #22962 -- Default values for ArrayField with migrations.

Fields normally try to force the default value to a string. As
translatable strings are not valid default values for ArrayField, we can
remove this behaviour which was causing issues with some migrations.

Thanks to @schinckel for the report.
This commit is contained in:
Marc Tamlyn 2014-07-15 12:30:34 +01:00
parent e5619330e2
commit ef9f109013
5 changed files with 102 additions and 1 deletions

View File

@ -94,6 +94,14 @@ class ArrayField(Field):
value = [self.base_field.to_python(val) for val in vals] value = [self.base_field.to_python(val) for val in vals]
return value 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): def value_to_string(self, obj):
values = [] values = []
vals = self._get_val_from_obj(obj) vals = self._get_val_from_obj(obj)

View File

@ -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,),
),
]

View File

@ -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,
),
]

View File

@ -4,10 +4,11 @@ import unittest
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from django.contrib.postgres.forms import SimpleArrayField, SplitArrayField from django.contrib.postgres.forms import SimpleArrayField, SplitArrayField
from django.core import exceptions, serializers from django.core import exceptions, serializers
from django.core.management import call_command
from django.db import models, IntegrityError, connection from django.db import models, IntegrityError, connection
from django.db.migrations.writer import MigrationWriter from django.db.migrations.writer import MigrationWriter
from django import forms from django import forms
from django.test import TestCase from django.test import TestCase, override_settings
from django.utils import timezone from django.utils import timezone
from .models import IntegerArrayModel, NullableIntegerArrayModel, CharArrayModel, DateTimeArrayModel, NestedIntegerArrayModel from .models import IntegerArrayModel, NullableIntegerArrayModel, CharArrayModel, DateTimeArrayModel, NestedIntegerArrayModel
@ -226,6 +227,13 @@ class TestMigrations(TestCase):
statement, imports = MigrationWriter.serialize(field) statement, imports = MigrationWriter.serialize(field)
self.assertEqual(statement, 'django.contrib.postgres.fields.ArrayField(models.CharField(max_length=20), size=None)') 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') @unittest.skipUnless(connection.vendor == 'postgresql', 'PostgreSQL required')
class TestSerialization(TestCase): class TestSerialization(TestCase):