From cc22b009e05456e3d9cf3c152fe47fa27772be5e Mon Sep 17 00:00:00 2001 From: Markus Holtermann Date: Wed, 11 Feb 2015 10:14:53 +0100 Subject: [PATCH] Refs #24264 -- Added failing test case for updating a FK when changing a PK When the primary key column is altered, foreign keys of referencing models must be aware of a possible data type change as well and thus need to be re-rendered. Thanks Tim Graham for the report. --- .../migrations_test_apps/alter_fk/__init__.py | 0 .../alter_fk/author_app/__init__.py | 0 .../author_app/migrations/0001_initial.py | 20 +++++++++++ .../author_app/migrations/0002_alter_id.py | 20 +++++++++++ .../author_app/migrations/__init__.py | 0 .../alter_fk/book_app/__init__.py | 0 .../book_app/migrations/0001_initial.py | 22 ++++++++++++ .../alter_fk/book_app/migrations/__init__.py | 0 tests/migrations/test_executor.py | 35 +++++++++++++++++++ 9 files changed, 97 insertions(+) create mode 100644 tests/migrations/migrations_test_apps/alter_fk/__init__.py create mode 100644 tests/migrations/migrations_test_apps/alter_fk/author_app/__init__.py create mode 100644 tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0001_initial.py create mode 100644 tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0002_alter_id.py create mode 100644 tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/__init__.py create mode 100644 tests/migrations/migrations_test_apps/alter_fk/book_app/__init__.py create mode 100644 tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py create mode 100644 tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/__init__.py diff --git a/tests/migrations/migrations_test_apps/alter_fk/__init__.py b/tests/migrations/migrations_test_apps/alter_fk/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/migrations/migrations_test_apps/alter_fk/author_app/__init__.py b/tests/migrations/migrations_test_apps/alter_fk/author_app/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0001_initial.py new file mode 100644 index 0000000000..8df44dfeef --- /dev/null +++ b/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0001_initial.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Author', + fields=[ + ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True)), + ('name', models.CharField(max_length=50)), + ], + ), + ] diff --git a/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0002_alter_id.py b/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0002_alter_id.py new file mode 100644 index 0000000000..ffce7dbd70 --- /dev/null +++ b/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/0002_alter_id.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('author_app', '0001_initial'), + ('book_app', '0001_initial'), # Forces the book table to alter the FK + ] + + operations = [ + migrations.AlterField( + model_name='author', + name='id', + field=models.CharField(max_length=10, primary_key=True), + ), + ] diff --git a/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/__init__.py b/tests/migrations/migrations_test_apps/alter_fk/author_app/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/migrations/migrations_test_apps/alter_fk/book_app/__init__.py b/tests/migrations/migrations_test_apps/alter_fk/book_app/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py new file mode 100644 index 0000000000..c929e4f075 --- /dev/null +++ b/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0001_initial.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('author_app', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Book', + fields=[ + ('id', models.AutoField(serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=50)), + ('author', models.ForeignKey('author_app.Author')), + ], + ), + ] diff --git a/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/__init__.py b/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/migrations/test_executor.py b/tests/migrations/test_executor.py index b88307ceea..b05eb04514 100644 --- a/tests/migrations/test_executor.py +++ b/tests/migrations/test_executor.py @@ -376,6 +376,41 @@ class ExecutorTests(MigrationTestBase): ] self.assertEqual(call_args_list, expected) + @override_settings( + INSTALLED_APPS=[ + "migrations.migrations_test_apps.alter_fk.author_app", + "migrations.migrations_test_apps.alter_fk.book_app", + ] + ) + def test_alter_id_type_with_fk(self): + try: + executor = MigrationExecutor(connection) + self.assertTableNotExists("author_app_author") + self.assertTableNotExists("book_app_book") + # Apply initial migrations + executor.migrate([ + ("author_app", "0001_initial"), + ("book_app", "0001_initial"), + ]) + self.assertTableExists("author_app_author") + self.assertTableExists("book_app_book") + # Rebuild the graph to reflect the new DB state + executor.loader.build_graph() + + # Apply PK type alteration + executor.migrate([("author_app", "0002_alter_id")]) + + # Rebuild the graph to reflect the new DB state + executor.loader.build_graph() + finally: + # We can't simply unapply the migrations here because there is no + # implicit cast from VARCHAR to INT on the database level. + with connection.schema_editor() as editor: + editor.execute(editor.sql_delete_table % {"table": "book_app_book"}) + editor.execute(editor.sql_delete_table % {"table": "author_app_author"}) + self.assertTableNotExists("author_app_author") + self.assertTableNotExists("book_app_book") + class FakeLoader(object): def __init__(self, graph, applied):