Fixed #19657 -- Made sql commands honor allow_migrate

Thanks Manel Clos for the report and the initial patch, and
Marc Tamlyn and Tim Graham for the review.
This commit is contained in:
Claude Paroz 2013-10-16 17:58:05 +02:00
parent 91c77eeab8
commit 2992f42861
2 changed files with 35 additions and 8 deletions

View File

@ -7,8 +7,15 @@ import warnings
from django.conf import settings from django.conf import settings
from django.core.management.base import CommandError from django.core.management.base import CommandError
from django.db import models from django.db import models, router
from django.db.models import get_models
def filtered_app_models(app, db_alias, include_auto_created=False):
"""
Return app models allowed to be synchronized on provided db.
"""
return [model for model in models.get_models(app, include_auto_created=include_auto_created)
if router.allow_migrate(db_alias, model)]
def sql_create(app, style, connection): def sql_create(app, style, connection):
@ -31,7 +38,7 @@ def sql_create(app, style, connection):
known_models = set(model for model in connection.introspection.installed_models(tables) if model not in app_models) known_models = set(model for model in connection.introspection.installed_models(tables) if model not in app_models)
pending_references = {} pending_references = {}
for model in app_models: for model in filtered_app_models(app, connection.alias, include_auto_created=True):
output, references = connection.creation.sql_create_model(model, style, known_models) output, references = connection.creation.sql_create_model(model, style, known_models)
final_output.extend(output) final_output.extend(output)
for refto, refs in references.items(): for refto, refs in references.items():
@ -78,7 +85,7 @@ def sql_delete(app, style, connection):
to_delete = set() to_delete = set()
references_to_delete = {} references_to_delete = {}
app_models = models.get_models(app, include_auto_created=True) app_models = filtered_app_models(app, connection.alias, include_auto_created=True)
for model in app_models: for model in app_models:
if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names: if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
# The table exists, so it needs to be dropped # The table exists, so it needs to be dropped
@ -122,7 +129,7 @@ def sql_custom(app, style, connection):
"Returns a list of the custom table modifying SQL statements for the given app." "Returns a list of the custom table modifying SQL statements for the given app."
output = [] output = []
app_models = get_models(app) app_models = filtered_app_models(app, connection.alias)
for model in app_models: for model in app_models:
output.extend(custom_sql_for_model(model, style, connection)) output.extend(custom_sql_for_model(model, style, connection))
@ -133,7 +140,7 @@ def sql_custom(app, style, connection):
def sql_indexes(app, style, connection): def sql_indexes(app, style, connection):
"Returns a list of the CREATE INDEX SQL statements for all models in the given app." "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
output = [] output = []
for model in models.get_models(app, include_auto_created=True): for model in filtered_app_models(app, connection.alias, include_auto_created=True):
output.extend(connection.creation.sql_indexes_for_model(model, style)) output.extend(connection.creation.sql_indexes_for_model(model, style))
return output return output
@ -141,7 +148,7 @@ def sql_indexes(app, style, connection):
def sql_destroy_indexes(app, style, connection): def sql_destroy_indexes(app, style, connection):
"Returns a list of the DROP INDEX SQL statements for all models in the given app." "Returns a list of the DROP INDEX SQL statements for all models in the given app."
output = [] output = []
for model in models.get_models(app, include_auto_created=True): for model in filtered_app_models(app, connection.alias, include_auto_created=True):
output.extend(connection.creation.sql_destroy_indexes_for_model(model, style)) output.extend(connection.creation.sql_destroy_indexes_for_model(model, style))
return output return output

View File

@ -3,7 +3,7 @@ from __future__ import unicode_literals
from django.core.management.color import no_style from django.core.management.color import no_style
from django.core.management.sql import (sql_create, sql_delete, sql_indexes, from django.core.management.sql import (sql_create, sql_delete, sql_indexes,
sql_destroy_indexes, sql_all) sql_destroy_indexes, sql_all)
from django.db import connections, DEFAULT_DB_ALIAS, models from django.db import connections, DEFAULT_DB_ALIAS, models, router
from django.test import TestCase from django.test import TestCase
from django.utils import six from django.utils import six
@ -52,3 +52,23 @@ class SQLCommandsTestCase(TestCase):
self.assertEqual(self.count_ddl(output, 'CREATE TABLE'), 3) self.assertEqual(self.count_ddl(output, 'CREATE TABLE'), 3)
# PostgreSQL creates one additional index for CharField # PostgreSQL creates one additional index for CharField
self.assertIn(self.count_ddl(output, 'CREATE INDEX'), [3, 4]) self.assertIn(self.count_ddl(output, 'CREATE INDEX'), [3, 4])
class TestRouter(object):
def allow_migrate(self, db, model):
return False
class SQLCommandsRouterTestCase(TestCase):
def setUp(self):
self._old_routers = router.routers
router.routers = [TestRouter()]
def tearDown(self):
router.routers = self._old_routers
def test_router_honored(self):
app = models.get_app('commands_sql')
for sql_command in (sql_all, sql_create, sql_delete, sql_indexes, sql_destroy_indexes):
output = sql_command(app, no_style(), connections[DEFAULT_DB_ALIAS])
self.assertEqual(len(output), 0,
"%s command is not honoring routers" % sql_command.__name__)