Fixed #27054 -- Fixed makemigrations crash with a read-only database.

This commit is contained in:
Jim Nicholls 2016-08-13 19:33:58 +10:00 committed by Tim Graham
parent 97513269d7
commit 76ab885118
4 changed files with 45 additions and 4 deletions

View File

@ -6,6 +6,7 @@ from importlib import import_module
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.db.migrations.exceptions import MigrationSchemaMissing
from django.db.migrations.graph import MigrationGraph from django.db.migrations.graph import MigrationGraph
from django.db.migrations.recorder import MigrationRecorder from django.db.migrations.recorder import MigrationRecorder
from django.utils import six from django.utils import six
@ -273,7 +274,12 @@ class MigrationLoader(object):
unapplied dependencies. unapplied dependencies.
""" """
recorder = MigrationRecorder(connection) recorder = MigrationRecorder(connection)
try:
applied = recorder.applied_migrations() applied = recorder.applied_migrations()
except MigrationSchemaMissing:
# Skip check if the django_migrations table is missing and can't be
# created.
return
for migration in applied: for migration in applied:
# If the migration is unknown, skip it. # If the migration is unknown, skip it.
if migration not in self.graph.nodes: if migration not in self.graph.nodes:

View File

@ -54,3 +54,5 @@ Bugfixes
PostGIS (:ticket:`27014`). PostGIS (:ticket:`27014`).
* Reallowed the ``{% for %}`` tag to unpack any iterable (:ticket:`27058`). * Reallowed the ``{% for %}`` tag to unpack any iterable (:ticket:`27058`).
* Fixed ``makemigrations`` crash if a database is read-only (:ticket:`27054`).

View File

@ -12,7 +12,9 @@ from django.core.management import CommandError, call_command
from django.db import ( from django.db import (
ConnectionHandler, DatabaseError, connection, connections, models, ConnectionHandler, DatabaseError, connection, connections, models,
) )
from django.db.migrations.exceptions import InconsistentMigrationHistory from django.db.migrations.exceptions import (
InconsistentMigrationHistory, MigrationSchemaMissing,
)
from django.db.migrations.recorder import MigrationRecorder from django.db.migrations.recorder import MigrationRecorder
from django.test import ignore_warnings, mock, override_settings from django.test import ignore_warnings, mock, override_settings
from django.utils import six from django.utils import six
@ -595,6 +597,27 @@ class MakeMigrationsTests(MigrationTestBase):
init_file = os.path.join(migration_dir, '__init__.py') init_file = os.path.join(migration_dir, '__init__.py')
self.assertTrue(os.path.exists(init_file)) self.assertTrue(os.path.exists(init_file))
def test_makemigrations_other_datbase_is_readonly(self):
"""
makemigrations ignores the non-default database if it's read-only.
"""
def patched_ensure_schema(migration_recorder):
from django.db import connections
if migration_recorder.connection is connections['other']:
raise MigrationSchemaMissing()
else:
return mock.DEFAULT
self.assertTableNotExists('migrations_unicodemodel')
apps.register_model('migrations', UnicodeModel)
with mock.patch.object(
MigrationRecorder, 'ensure_schema',
autospec=True, side_effect=patched_ensure_schema):
with self.temporary_migration_module() as migration_dir:
call_command("makemigrations", "migrations", verbosity=0)
initial_file = os.path.join(migration_dir, "0001_initial.py")
self.assertTrue(os.path.exists(initial_file))
def test_failing_migration(self): def test_failing_migration(self):
# If a migration fails to serialize, it shouldn't generate an empty file. #21280 # If a migration fails to serialize, it shouldn't generate an empty file. #21280
apps.register_model('migrations', UnserializableModel) apps.register_model('migrations', UnserializableModel)

View File

@ -4,11 +4,12 @@ from unittest import skipIf
from django.db import connection, connections from django.db import connection, connections
from django.db.migrations.exceptions import ( from django.db.migrations.exceptions import (
AmbiguityError, InconsistentMigrationHistory, NodeNotFoundError, AmbiguityError, InconsistentMigrationHistory, MigrationSchemaMissing,
NodeNotFoundError,
) )
from django.db.migrations.loader import MigrationLoader from django.db.migrations.loader import MigrationLoader
from django.db.migrations.recorder import MigrationRecorder from django.db.migrations.recorder import MigrationRecorder
from django.test import TestCase, modify_settings, override_settings from django.test import TestCase, mock, modify_settings, override_settings
from django.utils import six from django.utils import six
@ -464,3 +465,12 @@ class LoaderTests(TestCase):
('app1', '4_auto'), ('app1', '4_auto'),
} }
self.assertEqual(plan, expected_plan) self.assertEqual(plan, expected_plan)
def test_readonly_database(self):
"""
check_consistent_history() ignores read-only databases, possibly
without a django_migrations table.
"""
with mock.patch.object(MigrationRecorder, 'ensure_schema', side_effect=MigrationSchemaMissing()):
loader = MigrationLoader(connection=None)
loader.check_consistent_history(connection)