Commit 715ccfde authored by Markus Holtermann's avatar Markus Holtermann Committed by Tim Graham
Browse files

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

Thanks to Andrey Antukh for the report.
parent ed2f9681
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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`).
+8 −0
Original line number Diff line number Diff line
@@ -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)

+26 −1
Original line number Diff line number Diff line
@@ -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):
        """