| 1 | From d60ed64ef60af199a87d04472c7fd43bba3f5ebc Mon Sep 17 00:00:00 2001
|
|---|
| 2 | From: Emre Yilmaz <mail@emreyilmaz.me>
|
|---|
| 3 | Date: Thu, 3 Dec 2015 18:51:39 +0200
|
|---|
| 4 | Subject: [PATCH] Fixed #25855 -- Added more accurate info to migration warning
|
|---|
| 5 | on runserver command.
|
|---|
| 6 |
|
|---|
| 7 | If one have migrations waiting to be applied, runserver command
|
|---|
| 8 | gives a warning with check_migrations() method. Updated it with
|
|---|
| 9 | more accurate messages. (Unapplied migrations count and list of apps
|
|---|
| 10 | waiting their migrations applied.)
|
|---|
| 11 |
|
|---|
| 12 | Also added related unit tests and changed the "your app" text to "your project" since runserver
|
|---|
| 13 | command has a project-wide usage.
|
|---|
| 14 | ---
|
|---|
| 15 | django/core/management/commands/runserver.py | 13 +++++++---
|
|---|
| 16 | .../app_waiting_migration/__init__.py | 0
|
|---|
| 17 | .../migrations/0001_initial.py | 21 ++++++++++++++++
|
|---|
| 18 | .../app_waiting_migration/migrations/__init__.py | 0
|
|---|
| 19 | .../admin_scripts/app_waiting_migration/models.py | 10 ++++++++
|
|---|
| 20 | tests/admin_scripts/tests.py | 28 ++++++++++++++++++++++
|
|---|
| 21 | 6 files changed, 69 insertions(+), 3 deletions(-)
|
|---|
| 22 | create mode 100644 tests/admin_scripts/app_waiting_migration/__init__.py
|
|---|
| 23 | create mode 100644 tests/admin_scripts/app_waiting_migration/migrations/0001_initial.py
|
|---|
| 24 | create mode 100644 tests/admin_scripts/app_waiting_migration/migrations/__init__.py
|
|---|
| 25 | create mode 100644 tests/admin_scripts/app_waiting_migration/models.py
|
|---|
| 26 |
|
|---|
| 27 | diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
|
|---|
| 28 | index 6d05fa8..e368751 100644
|
|---|
| 29 | --- a/django/core/management/commands/runserver.py
|
|---|
| 30 | +++ b/django/core/management/commands/runserver.py
|
|---|
| 31 | @@ -172,9 +172,16 @@ def check_migrations(self):
|
|---|
| 32 |
|
|---|
| 33 | plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
|
|---|
| 34 | if plan:
|
|---|
| 35 | - self.stdout.write(self.style.NOTICE(
|
|---|
| 36 | - "\nYou have unapplied migrations; your app may not work properly until they are applied."
|
|---|
| 37 | - ))
|
|---|
| 38 | + apps_waiting_migration = sorted(set(migration.app_label for migration, backwards in plan))
|
|---|
| 39 | + self.stdout.write(
|
|---|
| 40 | + self.style.NOTICE(
|
|---|
| 41 | + "\nYou have %(unpplied_migration_count)s unapplied migrations; your project may not work properly "
|
|---|
| 42 | + "until apps [%(apps_waiting_migration)s] have their migrations applied." % {
|
|---|
| 43 | + "unpplied_migration_count": len(plan),
|
|---|
| 44 | + "apps_waiting_migration": ", ".join(apps_waiting_migration)
|
|---|
| 45 | + }
|
|---|
| 46 | + )
|
|---|
| 47 | + )
|
|---|
| 48 | self.stdout.write(self.style.NOTICE("Run 'python manage.py migrate' to apply them.\n"))
|
|---|
| 49 |
|
|---|
| 50 | # Kept for backward compatibility
|
|---|
| 51 | diff --git a/tests/admin_scripts/app_waiting_migration/__init__.py b/tests/admin_scripts/app_waiting_migration/__init__.py
|
|---|
| 52 | new file mode 100644
|
|---|
| 53 | index 0000000..e69de29
|
|---|
| 54 | diff --git a/tests/admin_scripts/app_waiting_migration/migrations/0001_initial.py b/tests/admin_scripts/app_waiting_migration/migrations/0001_initial.py
|
|---|
| 55 | new file mode 100644
|
|---|
| 56 | index 0000000..52d594a
|
|---|
| 57 | --- /dev/null
|
|---|
| 58 | +++ b/tests/admin_scripts/app_waiting_migration/migrations/0001_initial.py
|
|---|
| 59 | @@ -0,0 +1,21 @@
|
|---|
| 60 | +from __future__ import unicode_literals
|
|---|
| 61 | +
|
|---|
| 62 | +from django.db import migrations, models
|
|---|
| 63 | +
|
|---|
| 64 | +
|
|---|
| 65 | +class Migration(migrations.Migration):
|
|---|
| 66 | +
|
|---|
| 67 | + initial = True
|
|---|
| 68 | +
|
|---|
| 69 | + dependencies = [
|
|---|
| 70 | + ]
|
|---|
| 71 | +
|
|---|
| 72 | + operations = [
|
|---|
| 73 | + migrations.CreateModel(
|
|---|
| 74 | + name='Bar',
|
|---|
| 75 | + fields=[
|
|---|
| 76 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|---|
| 77 | + ('name', models.CharField(max_length=255)),
|
|---|
| 78 | + ],
|
|---|
| 79 | + ),
|
|---|
| 80 | + ]
|
|---|
| 81 | diff --git a/tests/admin_scripts/app_waiting_migration/migrations/__init__.py b/tests/admin_scripts/app_waiting_migration/migrations/__init__.py
|
|---|
| 82 | new file mode 100644
|
|---|
| 83 | index 0000000..e69de29
|
|---|
| 84 | diff --git a/tests/admin_scripts/app_waiting_migration/models.py b/tests/admin_scripts/app_waiting_migration/models.py
|
|---|
| 85 | new file mode 100644
|
|---|
| 86 | index 0000000..5e9f0e3
|
|---|
| 87 | --- /dev/null
|
|---|
| 88 | +++ b/tests/admin_scripts/app_waiting_migration/models.py
|
|---|
| 89 | @@ -0,0 +1,10 @@
|
|---|
| 90 | +from __future__ import unicode_literals
|
|---|
| 91 | +
|
|---|
| 92 | +from django.db import models
|
|---|
| 93 | +
|
|---|
| 94 | +
|
|---|
| 95 | +class Bar(models.Model):
|
|---|
| 96 | + name = models.CharField(max_length=255)
|
|---|
| 97 | +
|
|---|
| 98 | + class Meta:
|
|---|
| 99 | + app_label = 'app_waiting_migration'
|
|---|
| 100 | diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py
|
|---|
| 101 | index 755fb0b..ccf36d3 100644
|
|---|
| 102 | --- a/tests/admin_scripts/tests.py
|
|---|
| 103 | +++ b/tests/admin_scripts/tests.py
|
|---|
| 104 | @@ -1383,6 +1383,34 @@ def test_readonly_database(self):
|
|---|
| 105 | self.assertIn("Not checking migrations", self.output.getvalue())
|
|---|
| 106 |
|
|---|
| 107 |
|
|---|
| 108 | +@override_settings(
|
|---|
| 109 | + MIGRATION_MODULES={
|
|---|
| 110 | + "admin_scripts.app_waiting_migration":
|
|---|
| 111 | + "app_waiting_migration.migrations"},
|
|---|
| 112 | + INSTALLED_APPS=["admin_scripts.app_waiting_migration"]
|
|---|
| 113 | +)
|
|---|
| 114 | +class ManageRunserverMigrationWarning(SimpleTestCase):
|
|---|
| 115 | + allow_database_queries = True
|
|---|
| 116 | +
|
|---|
| 117 | + def setUp(self):
|
|---|
| 118 | + from django.core.management.commands.runserver import Command
|
|---|
| 119 | +
|
|---|
| 120 | + self.output = StringIO()
|
|---|
| 121 | + self.runserver_command = Command(stdout=self.output)
|
|---|
| 122 | +
|
|---|
| 123 | + def test_migration_warning(self):
|
|---|
| 124 | +
|
|---|
| 125 | + self.runserver_command.check_migrations()
|
|---|
| 126 | + self.assertIn(
|
|---|
| 127 | + 'You have 1 unapplied migrations;',
|
|---|
| 128 | + self.output.getvalue()
|
|---|
| 129 | + )
|
|---|
| 130 | + self.assertIn(
|
|---|
| 131 | + 'until apps [app_waiting_migration] have',
|
|---|
| 132 | + self.output.getvalue()
|
|---|
| 133 | + )
|
|---|
| 134 | +
|
|---|
| 135 | +
|
|---|
| 136 | class ManageRunserverEmptyAllowedHosts(AdminScriptTestCase):
|
|---|
| 137 | def setUp(self):
|
|---|
| 138 | self.write_settings('settings.py', sdict={
|
|---|