Support Django 5.0 db_default attribute.

A DB default is not considered backward incompatible, as the default value is kept on DB-level.
See https://docs.djangoproject.com/en/dev/releases/5.0/#database-computed-default-values
This commit is contained in:
David Wobrock authored and David Wobrock committed 2024-03-29 12:39:30 +01:00
1 parent 3a557cbd7c
commit 18a39cb3fc
12 files changed
+127 -13

No files matched your search

+3
View File
@@ -8,6 +8,9 @@ RENAME_COLUMN = "app_rename_column"
RENAME_TABLE = "app_rename_table"
IGNORE_MIGRATION = "app_ignore_migration"
ADD_NOT_NULL_COLUMN_FOLLOWED_BY_DEFAULT = "app_add_not_null_column_followed_by_default"
ADD_NOT_NULL_COLUMN_FOLLOWED_BY_DB_DEFAULT = (
"app_add_not_null_column_followed_by_db_default"
)
ALTER_COLUMN = "app_alter_column"
ALTER_COLUMN_DROP_NOT_NULL = "app_alter_column_drop_not_null"
DROP_UNIQUE_TOGETHER = "app_unique_together"
+12
View File
@@ -2,7 +2,9 @@ from __future__ import annotations
import os
import unittest
from unittest import skipIf
import django
from django.conf import settings
from django.core.management import call_command
@@ -88,6 +90,11 @@ class BaseBackwardCompatibilityDetection:
app = fixtures.ADD_NOT_NULL_COLUMN_FOLLOWED_BY_DEFAULT
self._test_linter_finds_no_errors(app)
@skipIf(django.VERSION[0] < 5, "db_default was implemented in Django 5.0")
def test_accept_not_null_column_followed_by_adding_db_default(self):
app = fixtures.ADD_NOT_NULL_COLUMN_FOLLOWED_BY_DB_DEFAULT
self._test_linter_finds_no_errors(app)
def test_detect_alter_column(self):
app = fixtures.ALTER_COLUMN
self._test_linter_finds_no_errors(app)
@@ -128,6 +135,11 @@ class SqliteBackwardCompatibilityDetectionTestCase(
app = fixtures.MAKE_NOT_NULL_WITH_DJANGO_DEFAULT
self._test_linter_finds_errors(app)
@skipIf(django.VERSION[0] < 5, "db_default was implemented in Django 5.0")
def test_accept_not_null_column_followed_by_adding_db_default(self):
app = fixtures.ADD_NOT_NULL_COLUMN_FOLLOWED_BY_DB_DEFAULT
self._test_linter_finds_errors(app)
def test_detect_make_column_not_null_with_lib_default(self):
# The 'django-add-default-value' doesn't handle sqlite correctly
app = fixtures.MAKE_NOT_NULL_WITH_LIB_DEFAULT
@@ -0,0 +1,30 @@
# Generated by Django 5.0.1 on 2024-02-04 20:07
from __future__ import annotations
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="A",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("field", models.IntegerField()),
],
),
]
@@ -0,0 +1,21 @@
# Generated by Django 5.0.1 on 2024-02-04 20:07
from __future__ import annotations
import django.db.models.functions.math
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("app_add_not_null_column_followed_by_db_default", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="a",
name="not_null_field_db_default",
field=models.IntegerField(db_default=django.db.models.functions.math.Pi()),
),
]
@@ -0,0 +1,12 @@
from __future__ import annotations
from django.db import models
from django.db.models.functions import Pi
class A(models.Model):
field = models.IntegerField()
not_null_field_db_default = models.IntegerField(
null=False,
db_default=Pi(),
)
+8
View File
@@ -14,6 +14,8 @@ from __future__ import annotations
import os
import django
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -59,6 +61,12 @@ INSTALLED_APPS = [
"tests.test_project.app_create_index_exclusive",
]
if django.VERSION[0] >= 5:
# db_default attribute was only added in Django 5.0
INSTALLED_APPS.append(
"tests.test_project.app_add_not_null_column_followed_by_db_default"
)
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
+22
View File
@@ -66,6 +66,15 @@ class MySqlAnalyserTestCase(SqlAnalyserTestCase):
]
self.assertBackwardIncompatibleSql(sql)
def test_add_not_null_without_dropping_default(self):
sql = (
"ALTER TABLE `app_add_not_null_column_a` ADD COLUMN `new_not_null_field` integer DEFAULT 1 NOT NULL;",
)
self.assertValidSql(sql)
sql = "ALTER TABLE `app_add_not_null_column_followed_by_default_a` ADD COLUMN `not_null_field_db_default` integer DEFAULT (PI()) NOT NULL;"
self.assertValidSql(sql)
def test_add_not_null_followed_by_default(self):
sql = [
"ALTER TABLE `app_add_not_null_column_followed_by_default_a` ADD COLUMN `new_not_null_field` integer DEFAULT 1 NOT NULL;",
@@ -147,6 +156,15 @@ class SqliteAnalyserTestCase(SqlAnalyserTestCase):
]
self.assertBackwardIncompatibleSql(sql)
def test_add_not_null_without_dropping_default(self):
sql = [
'CREATE TABLE "new__app_add_not_null_column_followed_by_default_a" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "not_null_field_db_default" integer DEFAULT (PI()) NOT NULL, "field" integer NOT NULL, "not_null_field" integer NOT NULL);',
'INSERT INTO "new__app_add_not_null_column_followed_by_default_a" ("id", "field", "not_null_field") SELECT "id", "field", "not_null_field" FROM "app_add_not_null_column_followed_by_default_a";',
'DROP TABLE "app_add_not_null_column_followed_by_default_a";',
'ALTER TABLE "new__app_add_not_null_column_followed_by_default_a" RENAME TO "app_add_not_null_column_followed_by_default_a";',
]
self.assertBackwardIncompatibleSql(sql)
def test_create_table_with_not_null(self):
sql = 'CREATE TABLE "app_create_table_with_not_null_column_a" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "field" varchar(150) NOT NULL);'
self.assertValidSql(sql)
@@ -207,6 +225,10 @@ class PostgresqlAnalyserTestCase(SqlAnalyserTestCase):
sql = 'ALTER TABLE "app_alter_column_a" ALTER COLUMN "field" TYPE varchar(10) USING "field"::varchar(10);'
self.assertBackwardIncompatibleSql(sql)
def test_add_not_null_without_dropping_default(self):
sql = 'ALTER TABLE "app_add_not_null_column_followed_by_default_a" ADD COLUMN "not_null_field_db_default" integer DEFAULT (PI()) NOT NULL;'
self.assertValidSql(sql)
def test_not_null_followed_by_default(self):
sql = [
'ALTER TABLE "app_add_not_null_column_followed_by_default_a" ADD COLUMN "not_null_field" integer DEFAULT 1 NOT NULL;',