From 2dfc1066a0d31c7e443e1c7b8590b101a645bf2d Mon Sep 17 00:00:00 2001
From: Jacob Walls <jacobtylerwalls@gmail.com>
Date: Thu, 10 Jun 2021 11:15:32 -0400
Subject: [PATCH] Fixed #25250 -- Clarified partially recorded state of
 squashed migrations in showmigrations --list.

---
 django/core/management/commands/showmigrations.py | 9 ++++++++-
 tests/migrations/test_commands.py                 | 9 +++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/django/core/management/commands/showmigrations.py b/django/core/management/commands/showmigrations.py
index e62a1b8593..fa14edbbcc 100644
--- a/django/core/management/commands/showmigrations.py
+++ b/django/core/management/commands/showmigrations.py
@@ -4,6 +4,7 @@ from django.apps import apps
 from django.core.management.base import BaseCommand
 from django.db import DEFAULT_DB_ALIAS, connections
 from django.db.migrations.loader import MigrationLoader
+from django.db.migrations.recorder import MigrationRecorder
 
 
 class Command(BaseCommand):
@@ -69,6 +70,8 @@ class Command(BaseCommand):
         """
         # Load migrations from disk/DB
         loader = MigrationLoader(connection, ignore_no_migrations=True)
+        recorder = MigrationRecorder(connection)
+        recorded_migrations = recorder.applied_migrations()
         graph = loader.graph
         # If we were passed a list of apps, validate it
         if app_names:
@@ -91,7 +94,11 @@ class Command(BaseCommand):
                         applied_migration = loader.applied_migrations.get(plan_node)
                         # Mark it as applied/unapplied
                         if applied_migration:
-                            output = ' [X] %s' % title
+                            if plan_node in recorded_migrations:
+                                output = ' [X] %s' % title
+                            else:
+                                title += " Run 'manage.py migrate' to finish recording."
+                                output = ' [-] %s' % title
                             if self.verbosity >= 2 and hasattr(applied_migration, 'applied'):
                                 output += ' (applied at %s)' % applied_migration.applied.strftime('%Y-%m-%d %H:%M:%S')
                             self.stdout.write(output)
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index b253192a56..b0cb0bb0b6 100644
--- a/tests/migrations/test_commands.py
+++ b/tests/migrations/test_commands.py
@@ -928,6 +928,15 @@ class MigrateTests(MigrationTestBase):
         recorder = MigrationRecorder(connection)
         recorder.record_applied("migrations", "0001_initial")
         recorder.record_applied("migrations", "0002_second")
+        out = io.StringIO()
+        call_command('showmigrations', 'migrations', stdout=out, no_color=True)
+        self.assertEqual(
+            "migrations\n"
+            " [-] 0001_squashed_0002 (2 squashed migrations) "
+            "run 'manage.py migrate' to finish recording.\n",
+            out.getvalue().lower(),
+        )
+
         out = io.StringIO()
         call_command("migrate", "migrations", verbosity=0)
         call_command("showmigrations", "migrations", stdout=out, no_color=True)