Fixed #23738 -- Allowed migrating from NULL to NOT NULL with the same default value

Thanks to Andrey Antukh for the report.
This commit is contained in:
Markus Holtermann 2014-10-31 14:08:24 +01:00 committed by Tim Graham
parent ed2f96819c
commit 715ccfde24
4 changed files with 38 additions and 2 deletions

View File

@ -607,7 +607,7 @@ class BaseDatabaseSchemaEditor(object):
# directly run a (NOT) NULL alteration
actions = actions + null_actions
# Combine actions together if we can (e.g. postgres)
if self.connection.features.supports_combined_alters:
if self.connection.features.supports_combined_alters and actions:
sql, params = tuple(zip(*actions))
actions = [(", ".join(sql), reduce(operator.add, params))]
# Apply those actions

View File

@ -37,3 +37,6 @@ Bugfixes
* Added support for transactional spatial metadata initialization on
SpatiaLite 4.1+ (:ticket:`23152`).
* Fixed a migration crash that prevented changing a nullable field with a
default to non-nullable with the same default (:ticket:`23738`).

View File

@ -17,6 +17,14 @@ class Author(models.Model):
apps = new_apps
class AuthorWithDefaultHeight(models.Model):
name = models.CharField(max_length=255)
height = models.PositiveIntegerField(null=True, blank=True, default=42)
class Meta:
apps = new_apps
class AuthorWithM2M(models.Model):
name = models.CharField(max_length=255)

View File

@ -7,7 +7,7 @@ from django.db.models.fields import (BinaryField, BooleanField, CharField, Integ
PositiveIntegerField, SlugField, TextField)
from django.db.models.fields.related import ManyToManyField, ForeignKey
from django.db.transaction import atomic
from .models import (Author, AuthorWithM2M, Book, BookWithLongName,
from .models import (Author, AuthorWithDefaultHeight, AuthorWithM2M, Book, BookWithLongName,
BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename,
UniqueTest, Thing, TagThrough, BookWithM2MThrough, AuthorTag, AuthorWithM2MThrough,
AuthorWithEvenLongerName, BookWeak)
@ -448,6 +448,31 @@ class SchemaTests(TransactionTestCase):
self.assertEqual(Author.objects.get(name='Not null author').height, 12)
self.assertEqual(Author.objects.get(name='Null author').height, 42)
@unittest.skipUnless(connection.features.supports_combined_alters, "No combined ALTER support")
def test_alter_null_to_not_null_keeping_default(self):
"""
#23738 - Can change a nullable field with default to non-nullable
with the same default.
"""
# Create the table
with connection.schema_editor() as editor:
editor.create_model(AuthorWithDefaultHeight)
# Ensure the field is right to begin with
columns = self.column_classes(AuthorWithDefaultHeight)
self.assertTrue(columns['height'][1][6])
# Alter the height field to NOT NULL keeping the previous default
new_field = PositiveIntegerField(default=42)
new_field.set_attributes_from_name("height")
with connection.schema_editor() as editor:
editor.alter_field(
AuthorWithDefaultHeight,
AuthorWithDefaultHeight._meta.get_field_by_name("height")[0],
new_field,
)
# Ensure the field is right afterwards
columns = self.column_classes(AuthorWithDefaultHeight)
self.assertFalse(columns['height'][1][6])
@unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
def test_alter_fk(self):
"""