From 2a7cb57a7e144dcea6359b68076f0bfbf38ee3c1 Mon Sep 17 00:00:00 2001 From: Clinton Christian Date: Sat, 15 Jun 2024 03:14:59 -0400 Subject: [PATCH] Fixed #35508: WIP --- .../management/commands/squashmigrations.py | 36 ++++++++++++++++++- .../book_app/migrations/0002_alter_fk.py | 16 +++++++++ tests/migrations/test_commands.py | 19 ++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0002_alter_fk.py diff --git a/django/core/management/commands/squashmigrations.py b/django/core/management/commands/squashmigrations.py index 6b5ddeeba5..01ae9d7568 100644 --- a/django/core/management/commands/squashmigrations.py +++ b/django/core/management/commands/squashmigrations.py @@ -5,12 +5,13 @@ from django.apps import apps from django.conf import settings from django.core.management.base import BaseCommand, CommandError from django.core.management.utils import run_formatters -from django.db import DEFAULT_DB_ALIAS, connections, migrations +from django.db import DEFAULT_DB_ALIAS, connections, migrations, models from django.db.migrations.loader import AmbiguityError, MigrationLoader from django.db.migrations.migration import SwappableTuple from django.db.migrations.optimizer import MigrationOptimizer from django.db.migrations.writer import MigrationWriter from django.utils.version import get_docs_version +from django.db.migrations.operations.base import OperationCategory class Command(BaseCommand): @@ -36,6 +37,14 @@ class Command(BaseCommand): "migration_name", help="Migrations will be squashed until and including this migration.", ) + parser.add_argument( + "--ignore-dependencies", + "--ignore-deps", + action="store_false", + dest="ignore_dependencies", + help="Ignore dependencies, except for those included in the" + " initial migration.", + ) parser.add_argument( "--no-optimize", action="store_true", @@ -65,6 +74,7 @@ class Command(BaseCommand): app_label = options["app_label"] start_migration_name = options["start_migration_name"] migration_name = options["migration_name"] + ignore_dependencies = options["ignore_dependencies"] no_optimize = options["no_optimize"] squashed_name = options["squashed_name"] include_header = options["include_header"] @@ -140,6 +150,12 @@ class Command(BaseCommand): # We need to take all dependencies from the first migration in the list # as it may be 0002 depending on 0001 first_migration = True + ignore_restricted_categories = set([ + OperationCategory.ADDITION, + OperationCategory.ALTERATION + ]) + + for smigration in migrations_to_squash: if smigration.replaces: raise CommandError( @@ -147,7 +163,24 @@ class Command(BaseCommand): "normal migration first: https://docs.djangoproject.com/en/%s/" "topics/migrations/#squashing-migrations" % get_docs_version() ) + + + if not first_migration and ignore_dependencies: + filtered_operations = [] + + for operation in smigration.operations: + if (operation.category in ignore_restricted_categories + and isinstance(operation.field, models.fields.related.RelatedField)): + #and operation field app_label != app_label: + continue + + filtered_operations.append(operation) + + operations.extend(filtered_operations) + continue + operations.extend(smigration.operations) + for dependency in smigration.dependencies: if isinstance(dependency, SwappableTuple): if settings.AUTH_USER_MODEL == dependency.setting: @@ -156,6 +189,7 @@ class Command(BaseCommand): dependencies.add(dependency) elif dependency[0] != smigration.app_label or first_migration: dependencies.add(dependency) + first_migration = False if no_optimize: diff --git a/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0002_alter_fk.py b/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0002_alter_fk.py new file mode 100644 index 0000000000..f4797bda86 --- /dev/null +++ b/tests/migrations/migrations_test_apps/alter_fk/book_app/migrations/0002_alter_fk.py @@ -0,0 +1,16 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("author_app", "0001_initial"), + ("book_app", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="Book", + name="author2", + field=models.ForeignKey("author_app.Author", models.CASCADE), + ), + ] diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py index 6ef172ee6f..fc881d4cd2 100644 --- a/tests/migrations/test_commands.py +++ b/tests/migrations/test_commands.py @@ -3044,6 +3044,25 @@ class SquashMigrationsTests(MigrationTestBase): + black_warning, ) + @override_settings( + INSTALLED_APPS=[ + "migrations.migrations_test_apps.alter_fk.author_app", + "migrations.migrations_test_apps.alter_fk.book_app", + ] + ) + def test_squashmigrations_ignore_dependencies_alter_relation_multi_apps(self): + with self.temporary_migration_module( + module="migrations.migrations_test_apps.alter_fk.book_app"): + call_command( + "squashmigrations", + "book_app", + "0001", + "0002", + interactive=False, + ignore_dependencies=True, + verbosity=0, + ) + class AppLabelErrorTests(TestCase): """