The new signature enables better support for routing RunPython and RunSQL operations, especially w.r.t. reusable and third-party apps. This commit also takes advantage of the deprecation cycle for the old signature to remove the backward incompatibility introduced in #22583; RunPython and RunSQL won't call allow_migrate() when when the router has the old signature. Thanks Aymeric Augustin and Tim Graham for helping shape up the patch. Refs 22583.
This commit is contained in:
parent
dd0b487872
commit
bed504d70b
|
@ -66,7 +66,7 @@ def create_permissions(app_config, verbosity=2, interactive=True, using=DEFAULT_
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not router.allow_migrate(using, Permission):
|
if not router.allow_migrate_model(using, Permission):
|
||||||
return
|
return
|
||||||
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
|
@ -17,7 +17,7 @@ def update_contenttypes(app_config, verbosity=2, interactive=True, using=DEFAULT
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not router.allow_migrate(using, ContentType):
|
if not router.allow_migrate_model(using, ContentType):
|
||||||
return
|
return
|
||||||
|
|
||||||
ContentType.objects.clear_cache()
|
ContentType.objects.clear_cache()
|
||||||
|
|
|
@ -33,6 +33,7 @@ class Migration(migrations.Migration):
|
||||||
migrations.RunPython(
|
migrations.RunPython(
|
||||||
migrations.RunPython.noop,
|
migrations.RunPython.noop,
|
||||||
add_legacy_name,
|
add_legacy_name,
|
||||||
|
hints={'model_name': 'contenttype'},
|
||||||
),
|
),
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='contenttype',
|
model_name='contenttype',
|
||||||
|
|
|
@ -14,7 +14,7 @@ def create_default_site(app_config, verbosity=2, interactive=True, using=DEFAULT
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not router.allow_migrate(using, Site):
|
if not router.allow_migrate_model(using, Site):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not Site.objects.using(using).exists():
|
if not Site.objects.using(using).exists():
|
||||||
|
|
|
@ -30,6 +30,7 @@ class Options(object):
|
||||||
self.abstract = False
|
self.abstract = False
|
||||||
self.managed = True
|
self.managed = True
|
||||||
self.proxy = False
|
self.proxy = False
|
||||||
|
self.swapped = False
|
||||||
|
|
||||||
|
|
||||||
class BaseDatabaseCache(BaseCache):
|
class BaseDatabaseCache(BaseCache):
|
||||||
|
|
|
@ -38,7 +38,7 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
def create_table(self, database, tablename):
|
def create_table(self, database, tablename):
|
||||||
cache = BaseDatabaseCache(tablename, {})
|
cache = BaseDatabaseCache(tablename, {})
|
||||||
if not router.allow_migrate(database, cache.cache_model_class):
|
if not router.allow_migrate_model(database, cache.cache_model_class):
|
||||||
return
|
return
|
||||||
connection = connections[database]
|
connection = connections[database]
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ class Command(BaseCommand):
|
||||||
for model in serializers.sort_dependencies(app_list.items()):
|
for model in serializers.sort_dependencies(app_list.items()):
|
||||||
if model in excluded_models:
|
if model in excluded_models:
|
||||||
continue
|
continue
|
||||||
if not model._meta.proxy and router.allow_migrate(using, model):
|
if not model._meta.proxy and router.allow_migrate_model(using, model):
|
||||||
if use_base_manager:
|
if use_base_manager:
|
||||||
objects = model._base_manager
|
objects = model._base_manager
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -139,7 +139,7 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
objects_in_fixture += 1
|
objects_in_fixture += 1
|
||||||
if router.allow_migrate(self.using, obj.object.__class__):
|
if router.allow_migrate_model(self.using, obj.object.__class__):
|
||||||
loaded_objects_in_fixture += 1
|
loaded_objects_in_fixture += 1
|
||||||
self.models.add(obj.object.__class__)
|
self.models.add(obj.object.__class__)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -107,7 +107,7 @@ class BaseDatabaseCreation(object):
|
||||||
def get_objects():
|
def get_objects():
|
||||||
for model in serializers.sort_dependencies(app_list):
|
for model in serializers.sort_dependencies(app_list):
|
||||||
if (not model._meta.proxy and model._meta.managed and
|
if (not model._meta.proxy and model._meta.managed and
|
||||||
router.allow_migrate(self.connection.alias, model)):
|
router.allow_migrate_model(self.connection.alias, model)):
|
||||||
queryset = model._default_manager.using(self.connection.alias).order_by(model._meta.pk.name)
|
queryset = model._default_manager.using(self.connection.alias).order_by(model._meta.pk.name)
|
||||||
for obj in queryset.iterator():
|
for obj in queryset.iterator():
|
||||||
yield obj
|
yield obj
|
||||||
|
|
|
@ -99,15 +99,17 @@ class Operation(object):
|
||||||
"""
|
"""
|
||||||
return self.references_model(model_name, app_label)
|
return self.references_model(model_name, app_label)
|
||||||
|
|
||||||
def allowed_to_migrate(self, connection_alias, model, hints=None):
|
def allow_migrate_model(self, connection_alias, model):
|
||||||
"""
|
"""
|
||||||
Returns if we're allowed to migrate the model.
|
Returns if we're allowed to migrate the model.
|
||||||
|
|
||||||
|
This is a thin wrapper around router.allow_migrate_model() that
|
||||||
|
preemptively rejects any proxy, swapped out, or unmanaged model.
|
||||||
"""
|
"""
|
||||||
# Always skip if proxy, swapped out, or unmanaged.
|
if model._meta.proxy or model._meta.swapped or not model._meta.managed:
|
||||||
if model and (model._meta.proxy or model._meta.swapped or not model._meta.managed):
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return router.allow_migrate(connection_alias, model, **(hints or {}))
|
return router.allow_migrate_model(connection_alias, model)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s %s%s>" % (
|
return "<%s %s%s>" % (
|
||||||
|
|
|
@ -52,7 +52,7 @@ class AddField(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
to_model = to_state.apps.get_model(app_label, self.model_name)
|
to_model = to_state.apps.get_model(app_label, self.model_name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.apps.get_model(app_label, self.model_name)
|
from_model = from_state.apps.get_model(app_label, self.model_name)
|
||||||
field = to_model._meta.get_field(self.name)
|
field = to_model._meta.get_field(self.name)
|
||||||
if not self.preserve_default:
|
if not self.preserve_default:
|
||||||
|
@ -66,7 +66,7 @@ class AddField(Operation):
|
||||||
|
|
||||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
from_model = from_state.apps.get_model(app_label, self.model_name)
|
from_model = from_state.apps.get_model(app_label, self.model_name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, from_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, from_model):
|
||||||
schema_editor.remove_field(from_model, from_model._meta.get_field(self.name))
|
schema_editor.remove_field(from_model, from_model._meta.get_field(self.name))
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
|
@ -117,12 +117,12 @@ class RemoveField(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
from_model = from_state.apps.get_model(app_label, self.model_name)
|
from_model = from_state.apps.get_model(app_label, self.model_name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, from_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, from_model):
|
||||||
schema_editor.remove_field(from_model, from_model._meta.get_field(self.name))
|
schema_editor.remove_field(from_model, from_model._meta.get_field(self.name))
|
||||||
|
|
||||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
to_model = to_state.apps.get_model(app_label, self.model_name)
|
to_model = to_state.apps.get_model(app_label, self.model_name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.apps.get_model(app_label, self.model_name)
|
from_model = from_state.apps.get_model(app_label, self.model_name)
|
||||||
schema_editor.add_field(from_model, to_model._meta.get_field(self.name))
|
schema_editor.add_field(from_model, to_model._meta.get_field(self.name))
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ class AlterField(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
to_model = to_state.apps.get_model(app_label, self.model_name)
|
to_model = to_state.apps.get_model(app_label, self.model_name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.apps.get_model(app_label, self.model_name)
|
from_model = from_state.apps.get_model(app_label, self.model_name)
|
||||||
from_field = from_model._meta.get_field(self.name)
|
from_field = from_model._meta.get_field(self.name)
|
||||||
to_field = to_model._meta.get_field(self.name)
|
to_field = to_model._meta.get_field(self.name)
|
||||||
|
@ -267,7 +267,7 @@ class RenameField(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
to_model = to_state.apps.get_model(app_label, self.model_name)
|
to_model = to_state.apps.get_model(app_label, self.model_name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.apps.get_model(app_label, self.model_name)
|
from_model = from_state.apps.get_model(app_label, self.model_name)
|
||||||
schema_editor.alter_field(
|
schema_editor.alter_field(
|
||||||
from_model,
|
from_model,
|
||||||
|
@ -277,7 +277,7 @@ class RenameField(Operation):
|
||||||
|
|
||||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
to_model = to_state.apps.get_model(app_label, self.model_name)
|
to_model = to_state.apps.get_model(app_label, self.model_name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.apps.get_model(app_label, self.model_name)
|
from_model = from_state.apps.get_model(app_label, self.model_name)
|
||||||
schema_editor.alter_field(
|
schema_editor.alter_field(
|
||||||
from_model,
|
from_model,
|
||||||
|
|
|
@ -55,12 +55,12 @@ class CreateModel(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
model = to_state.apps.get_model(app_label, self.name)
|
model = to_state.apps.get_model(app_label, self.name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, model):
|
if self.allow_migrate_model(schema_editor.connection.alias, model):
|
||||||
schema_editor.create_model(model)
|
schema_editor.create_model(model)
|
||||||
|
|
||||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
model = from_state.apps.get_model(app_label, self.name)
|
model = from_state.apps.get_model(app_label, self.name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, model):
|
if self.allow_migrate_model(schema_editor.connection.alias, model):
|
||||||
schema_editor.delete_model(model)
|
schema_editor.delete_model(model)
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
|
@ -111,12 +111,12 @@ class DeleteModel(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
model = from_state.apps.get_model(app_label, self.name)
|
model = from_state.apps.get_model(app_label, self.name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, model):
|
if self.allow_migrate_model(schema_editor.connection.alias, model):
|
||||||
schema_editor.delete_model(model)
|
schema_editor.delete_model(model)
|
||||||
|
|
||||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
model = to_state.apps.get_model(app_label, self.name)
|
model = to_state.apps.get_model(app_label, self.name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, model):
|
if self.allow_migrate_model(schema_editor.connection.alias, model):
|
||||||
schema_editor.create_model(model)
|
schema_editor.create_model(model)
|
||||||
|
|
||||||
def references_model(self, name, app_label=None):
|
def references_model(self, name, app_label=None):
|
||||||
|
@ -189,7 +189,7 @@ class RenameModel(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
new_model = to_state.apps.get_model(app_label, self.new_name)
|
new_model = to_state.apps.get_model(app_label, self.new_name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, new_model):
|
||||||
old_model = from_state.apps.get_model(app_label, self.old_name)
|
old_model = from_state.apps.get_model(app_label, self.old_name)
|
||||||
# Move the main table
|
# Move the main table
|
||||||
schema_editor.alter_db_table(
|
schema_editor.alter_db_table(
|
||||||
|
@ -287,7 +287,7 @@ class AlterModelTable(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
new_model = to_state.apps.get_model(app_label, self.name)
|
new_model = to_state.apps.get_model(app_label, self.name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, new_model):
|
||||||
old_model = from_state.apps.get_model(app_label, self.name)
|
old_model = from_state.apps.get_model(app_label, self.name)
|
||||||
schema_editor.alter_db_table(
|
schema_editor.alter_db_table(
|
||||||
new_model,
|
new_model,
|
||||||
|
@ -347,7 +347,7 @@ class AlterUniqueTogether(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
new_model = to_state.apps.get_model(app_label, self.name)
|
new_model = to_state.apps.get_model(app_label, self.name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, new_model):
|
||||||
old_model = from_state.apps.get_model(app_label, self.name)
|
old_model = from_state.apps.get_model(app_label, self.name)
|
||||||
schema_editor.alter_unique_together(
|
schema_editor.alter_unique_together(
|
||||||
new_model,
|
new_model,
|
||||||
|
@ -399,7 +399,7 @@ class AlterIndexTogether(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
new_model = to_state.apps.get_model(app_label, self.name)
|
new_model = to_state.apps.get_model(app_label, self.name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, new_model):
|
||||||
old_model = from_state.apps.get_model(app_label, self.name)
|
old_model = from_state.apps.get_model(app_label, self.name)
|
||||||
schema_editor.alter_index_together(
|
schema_editor.alter_index_together(
|
||||||
new_model,
|
new_model,
|
||||||
|
@ -448,7 +448,7 @@ class AlterOrderWithRespectTo(Operation):
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
to_model = to_state.apps.get_model(app_label, self.name)
|
to_model = to_state.apps.get_model(app_label, self.name)
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
if self.allow_migrate_model(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.apps.get_model(app_label, self.name)
|
from_model = from_state.apps.get_model(app_label, self.name)
|
||||||
# Remove a field if we need to
|
# Remove a field if we need to
|
||||||
if from_model._meta.order_with_respect_to and not to_model._meta.order_with_respect_to:
|
if from_model._meta.order_with_respect_to and not to_model._meta.order_with_respect_to:
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import router
|
||||||
|
|
||||||
from .base import Operation
|
from .base import Operation
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,13 +96,13 @@ class RunSQL(Operation):
|
||||||
state_operation.state_forwards(app_label, state)
|
state_operation.state_forwards(app_label, state)
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, None, hints=self.hints):
|
if router.allow_migrate(schema_editor.connection.alias, app_label, **self.hints):
|
||||||
self._run_sql(schema_editor, self.sql)
|
self._run_sql(schema_editor, self.sql)
|
||||||
|
|
||||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
if self.reverse_sql is None:
|
if self.reverse_sql is None:
|
||||||
raise NotImplementedError("You cannot reverse this operation")
|
raise NotImplementedError("You cannot reverse this operation")
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, None, hints=self.hints):
|
if router.allow_migrate(schema_editor.connection.alias, app_label, **self.hints):
|
||||||
self._run_sql(schema_editor, self.reverse_sql)
|
self._run_sql(schema_editor, self.reverse_sql)
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
|
@ -171,7 +173,7 @@ class RunPython(Operation):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, None, hints=self.hints):
|
if router.allow_migrate(schema_editor.connection.alias, app_label, **self.hints):
|
||||||
# We now execute the Python code in a context that contains a 'models'
|
# We now execute the Python code in a context that contains a 'models'
|
||||||
# object, representing the versioned models as an app registry.
|
# object, representing the versioned models as an app registry.
|
||||||
# We could try to override the global cache, but then people will still
|
# We could try to override the global cache, but then people will still
|
||||||
|
@ -181,7 +183,7 @@ class RunPython(Operation):
|
||||||
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
if self.reverse_code is None:
|
if self.reverse_code is None:
|
||||||
raise NotImplementedError("You cannot reverse this operation")
|
raise NotImplementedError("You cannot reverse this operation")
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, None, hints=self.hints):
|
if router.allow_migrate(schema_editor.connection.alias, app_label, **self.hints):
|
||||||
self.reverse_code(from_state.apps, schema_editor)
|
self.reverse_code(from_state.apps, schema_editor)
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
|
|
|
@ -1549,7 +1549,7 @@ class Model(six.with_metaclass(ModelBase)):
|
||||||
# Find the minimum max allowed length among all specified db_aliases.
|
# Find the minimum max allowed length among all specified db_aliases.
|
||||||
for db in settings.DATABASES.keys():
|
for db in settings.DATABASES.keys():
|
||||||
# skip databases where the model won't be created
|
# skip databases where the model won't be created
|
||||||
if not router.allow_migrate(db, cls):
|
if not router.allow_migrate_model(db, cls):
|
||||||
continue
|
continue
|
||||||
connection = connections[db]
|
connection = connections[db]
|
||||||
max_name_length = connection.ops.max_name_length()
|
max_name_length = connection.ops.max_name_length()
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import inspect
|
||||||
import os
|
import os
|
||||||
import pkgutil
|
import pkgutil
|
||||||
|
import warnings
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from threading import local
|
from threading import local
|
||||||
|
|
||||||
|
@ -7,6 +9,7 @@ from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils._os import upath
|
from django.utils._os import upath
|
||||||
|
from django.utils.deprecation import RemovedInDjango20Warning
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.module_loading import import_string
|
from django.utils.module_loading import import_string
|
||||||
|
|
||||||
|
@ -276,22 +279,42 @@ class ConnectionRouter(object):
|
||||||
return allow
|
return allow
|
||||||
return obj1._state.db == obj2._state.db
|
return obj1._state.db == obj2._state.db
|
||||||
|
|
||||||
def allow_migrate(self, db, model, **hints):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
for router in self.routers:
|
for router in self.routers:
|
||||||
try:
|
try:
|
||||||
method = router.allow_migrate
|
method = router.allow_migrate
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# If the router doesn't have a method, skip to the next one.
|
# If the router doesn't have a method, skip to the next one.
|
||||||
pass
|
continue
|
||||||
|
|
||||||
|
argspec = inspect.getargspec(router.allow_migrate)
|
||||||
|
if len(argspec.args) == 3 and not argspec.keywords:
|
||||||
|
warnings.warn(
|
||||||
|
"The signature of allow_migrate has changed from "
|
||||||
|
"allow_migrate(self, db, model) to "
|
||||||
|
"allow_migrate(self, db, app_label, model_name=None, **hints). "
|
||||||
|
"Support for the old signature will be removed in Django 2.0.",
|
||||||
|
RemovedInDjango20Warning)
|
||||||
|
model = hints.get('model')
|
||||||
|
allow = None if model is None else method(db, model)
|
||||||
else:
|
else:
|
||||||
allow = method(db, model, **hints)
|
allow = method(db, app_label, **hints)
|
||||||
|
|
||||||
if allow is not None:
|
if allow is not None:
|
||||||
return allow
|
return allow
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def allow_migrate_model(self, db, model):
|
||||||
|
return self.allow_migrate(
|
||||||
|
db,
|
||||||
|
model._meta.app_label,
|
||||||
|
model_name=model._meta.model_name,
|
||||||
|
model=model,
|
||||||
|
)
|
||||||
|
|
||||||
def get_migratable_models(self, app_config, db, include_auto_created=False):
|
def get_migratable_models(self, app_config, db, include_auto_created=False):
|
||||||
"""
|
"""
|
||||||
Return app models allowed to be synchronized on provided db.
|
Return app models allowed to be synchronized on provided db.
|
||||||
"""
|
"""
|
||||||
models = app_config.get_models(include_auto_created=include_auto_created)
|
models = app_config.get_models(include_auto_created=include_auto_created)
|
||||||
return [model for model in models if self.allow_migrate(db, model)]
|
return [model for model in models if self.allow_migrate_model(db, model)]
|
||||||
|
|
|
@ -46,7 +46,7 @@ method of database routers as ``**hints``:
|
||||||
|
|
||||||
class MyRouter(object):
|
class MyRouter(object):
|
||||||
|
|
||||||
def allow_migrate(self, db, model, **hints):
|
def allow_migrate(self, db, app_label, model_name=None, **hints):
|
||||||
if 'target_db' in hints:
|
if 'target_db' in hints:
|
||||||
return db == hints['target_db']
|
return db == hints['target_db']
|
||||||
return True
|
return True
|
||||||
|
@ -68,6 +68,10 @@ Then, to leverage this in your migrations, do the following::
|
||||||
migrations.RunPython(forwards, hints={'target_db': 'default'}),
|
migrations.RunPython(forwards, hints={'target_db': 'default'}),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
If your ``RunPython`` or ``RunSQL`` operation only affects one model, it's good
|
||||||
|
practice to pass ``model_name`` as a hint to make it as transparent as possible
|
||||||
|
to the router. This is especially important for reusable and third-party apps.
|
||||||
|
|
||||||
Migrations that add unique fields
|
Migrations that add unique fields
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,10 @@ details on these changes.
|
||||||
* Ability to specify ``ContentType.name`` when creating a content type instance
|
* Ability to specify ``ContentType.name`` when creating a content type instance
|
||||||
will be removed.
|
will be removed.
|
||||||
|
|
||||||
|
* Support for the old signature of ``allow_migrate`` will be removed. It changed
|
||||||
|
from ``allow_migrate(self, db, model)`` to
|
||||||
|
``allow_migrate(self, db, app_label, model_name=None, **hints)``.
|
||||||
|
|
||||||
.. _deprecation-removed-in-1.9:
|
.. _deprecation-removed-in-1.9:
|
||||||
|
|
||||||
1.9
|
1.9
|
||||||
|
|
|
@ -480,11 +480,13 @@ Migrations
|
||||||
method/attribute were added to ease in making ``RunPython`` and ``RunSQL``
|
method/attribute were added to ease in making ``RunPython`` and ``RunSQL``
|
||||||
operations reversible.
|
operations reversible.
|
||||||
|
|
||||||
* The :class:`~django.db.migrations.operations.RunPython` and
|
* The migration operations :class:`~django.db.migrations.operations.RunPython`
|
||||||
:class:`~django.db.migrations.operations.RunSQL` operations now accept a
|
and :class:`~django.db.migrations.operations.RunSQL` now call the
|
||||||
``hints`` parameter that will be passed to :meth:`allow_migrate`. To take
|
:meth:`allow_migrate` method of database routers. The router can use the
|
||||||
advantage of this feature you must ensure that the ``allow_migrate()`` method
|
newly introduced ``app_label`` and ``hints`` arguments to make a routing
|
||||||
of all your routers accept ``**hints``.
|
decision. To take advantage of this feature you need to update the router to
|
||||||
|
the new ``allow_migrate`` signature, see the :ref:`deprecation section
|
||||||
|
<deprecated-signature-of-allow-migrate>` for more details.
|
||||||
|
|
||||||
Models
|
Models
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
@ -1146,14 +1148,6 @@ Miscellaneous
|
||||||
* :func:`django.utils.translation.get_language()` now returns ``None`` instead
|
* :func:`django.utils.translation.get_language()` now returns ``None`` instead
|
||||||
of :setting:`LANGUAGE_CODE` when translations are temporarily deactivated.
|
of :setting:`LANGUAGE_CODE` when translations are temporarily deactivated.
|
||||||
|
|
||||||
* The migration operations :class:`~django.db.migrations.operations.RunPython`
|
|
||||||
and :class:`~django.db.migrations.operations.RunSQL` now call the
|
|
||||||
:meth:`allow_migrate` method of database routers. In these cases the
|
|
||||||
``model`` argument of ``allow_migrate()`` is set to ``None``, so the router
|
|
||||||
must properly handle this value. This is most useful when used together with
|
|
||||||
the newly introduced ``hints`` parameter for these operations, but it can
|
|
||||||
also be used to disable migrations from running on a particular database.
|
|
||||||
|
|
||||||
* The ``name`` field of :class:`django.contrib.contenttypes.models.ContentType`
|
* The ``name`` field of :class:`django.contrib.contenttypes.models.ContentType`
|
||||||
has been removed by a migration and replaced by a property. That means it's
|
has been removed by a migration and replaced by a property. That means it's
|
||||||
not possible to query or filter a ``ContentType`` by this field any longer.
|
not possible to query or filter a ``ContentType`` by this field any longer.
|
||||||
|
@ -1651,6 +1645,23 @@ aggregate methods are deprecated and should be replaced by their function-based
|
||||||
aggregate equivalents (``Collect``, ``Extent``, ``Extent3D``, ``MakeLine``, and
|
aggregate equivalents (``Collect``, ``Extent``, ``Extent3D``, ``MakeLine``, and
|
||||||
``Union``).
|
``Union``).
|
||||||
|
|
||||||
|
.. _deprecated-signature-of-allow-migrate:
|
||||||
|
|
||||||
|
Signature of the ``allow_migrate`` router method
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The signature of the :meth:`allow_migrate` method of database routers has
|
||||||
|
changed from ``allow_migrate(db, model)`` to
|
||||||
|
``allow_migrate(db, app_label, model_name=None, **hints)``.
|
||||||
|
|
||||||
|
When ``model_name`` is set, the value that was previously given through the
|
||||||
|
``model`` positional argument may now be found inside the ``hints`` dictionary
|
||||||
|
under the key ``'model'``.
|
||||||
|
|
||||||
|
After switching to the new signature the router will also be called by the
|
||||||
|
:class:`~django.db.migrations.operations.RunPython` and
|
||||||
|
:class:`~django.db.migrations.operations.RunSQL` operations.
|
||||||
|
|
||||||
.. removed-features-1.8:
|
.. removed-features-1.8:
|
||||||
|
|
||||||
Features removed in 1.8
|
Features removed in 1.8
|
||||||
|
|
|
@ -226,19 +226,19 @@ operations to ``cache_replica``, and all write operations to
|
||||||
|
|
||||||
def db_for_read(self, model, **hints):
|
def db_for_read(self, model, **hints):
|
||||||
"All cache read operations go to the replica"
|
"All cache read operations go to the replica"
|
||||||
if model._meta.app_label in ('django_cache',):
|
if model._meta.app_label == 'django_cache':
|
||||||
return 'cache_replica'
|
return 'cache_replica'
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def db_for_write(self, model, **hints):
|
def db_for_write(self, model, **hints):
|
||||||
"All cache write operations go to primary"
|
"All cache write operations go to primary"
|
||||||
if model._meta.app_label in ('django_cache',):
|
if model._meta.app_label == 'django_cache':
|
||||||
return 'cache_primary'
|
return 'cache_primary'
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def allow_migrate(self, db, model):
|
def allow_migrate(self, db, app_label, model_name=None, **hints):
|
||||||
"Only install the cache model on primary"
|
"Only install the cache model on primary"
|
||||||
if model._meta.app_label in ('django_cache',):
|
if app_label == 'django_cache':
|
||||||
return db == 'cache_primary'
|
return db == 'cache_primary'
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ A database Router is a class that provides up to four methods:
|
||||||
provided in the ``hints`` dictionary. Details on valid hints are
|
provided in the ``hints`` dictionary. Details on valid hints are
|
||||||
provided :ref:`below <topics-db-multi-db-hints>`.
|
provided :ref:`below <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
Returns None if there is no suggestion.
|
Returns ``None`` if there is no suggestion.
|
||||||
|
|
||||||
.. method:: db_for_write(model, **hints)
|
.. method:: db_for_write(model, **hints)
|
||||||
|
|
||||||
|
@ -140,32 +140,53 @@ A database Router is a class that provides up to four methods:
|
||||||
provided in the ``hints`` dictionary. Details on valid hints are
|
provided in the ``hints`` dictionary. Details on valid hints are
|
||||||
provided :ref:`below <topics-db-multi-db-hints>`.
|
provided :ref:`below <topics-db-multi-db-hints>`.
|
||||||
|
|
||||||
Returns None if there is no suggestion.
|
Returns ``None`` if there is no suggestion.
|
||||||
|
|
||||||
.. method:: allow_relation(obj1, obj2, **hints)
|
.. method:: allow_relation(obj1, obj2, **hints)
|
||||||
|
|
||||||
Return True if a relation between obj1 and obj2 should be
|
Return ``True`` if a relation between ``obj1`` and ``obj2`` should be
|
||||||
allowed, False if the relation should be prevented, or None if
|
allowed, ``False`` if the relation should be prevented, or ``None`` if
|
||||||
the router has no opinion. This is purely a validation operation,
|
the router has no opinion. This is purely a validation operation,
|
||||||
used by foreign key and many to many operations to determine if a
|
used by foreign key and many to many operations to determine if a
|
||||||
relation should be allowed between two objects.
|
relation should be allowed between two objects.
|
||||||
|
|
||||||
.. method:: allow_migrate(db, model, **hints)
|
.. method:: allow_migrate(db, app_label, model_name=None, **hints)
|
||||||
|
|
||||||
Determine if the ``model`` should have tables/indexes created in the
|
Determine if the migration operation is allowed to run on the database with
|
||||||
database with alias ``db``. Return True if the model should be
|
alias ``db``. Return ``True`` if the operation should run, ``False`` if it
|
||||||
migrated, False if it should not be migrated, or None if
|
shouldn't run, or ``None`` if the router has no opinion.
|
||||||
the router has no opinion. This method can be used to determine
|
|
||||||
the availability of a model on a given database.
|
|
||||||
|
|
||||||
Note that migrations will just silently not perform any operations
|
The ``app_label`` positional argument is the label of the application
|
||||||
on a model for which this returns ``False``. This may result in broken
|
being migrated.
|
||||||
ForeignKeys, extra tables or missing tables if you change it once you
|
|
||||||
have applied some migrations.
|
|
||||||
|
|
||||||
The value passed for ``model`` may be a
|
``model_name`` is set by most migration operations to the value of
|
||||||
:ref:`historical model <historical-models>`, and thus not have any
|
``model._meta.model_name`` (the lowercased version of the model
|
||||||
custom attributes, methods or managers. You should only rely on ``_meta``.
|
``__name__``) of the model being migrated. Its value is ``None`` for the
|
||||||
|
:class:`~django.db.migrations.operations.RunPython` and
|
||||||
|
:class:`~django.db.migrations.operations.RunSQL` operations unless they
|
||||||
|
provide it using hints.
|
||||||
|
|
||||||
|
``hints`` are used by certain operations to communicate additional
|
||||||
|
information to the router.
|
||||||
|
|
||||||
|
When ``model_name`` is set, ``hints`` normally contains the model class
|
||||||
|
under the key ``'model'``. Note that it may be a :ref:`historical model
|
||||||
|
<historical-models>`, and thus not have any custom attributes, methods, or
|
||||||
|
managers. You should only rely on ``_meta``.
|
||||||
|
|
||||||
|
This method can also be used to determine the availability of a model on a
|
||||||
|
given database.
|
||||||
|
|
||||||
|
Note that migrations will just silently not perform any operations on a
|
||||||
|
model for which this returns ``False``. This may result in broken foreign
|
||||||
|
keys, extra tables, or missing tables if you change it once you have
|
||||||
|
applied some migrations.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.8
|
||||||
|
|
||||||
|
The signature of ``allow_migrate`` has changed significantly from previous
|
||||||
|
versions. See the :ref:`deprecation notes
|
||||||
|
<deprecated-signature-of-allow-migrate>` for more details.
|
||||||
|
|
||||||
A router doesn't have to provide *all* these methods -- it may omit one
|
A router doesn't have to provide *all* these methods -- it may omit one
|
||||||
or more of them. If one of the methods is omitted, Django will skip
|
or more of them. If one of the methods is omitted, Django will skip
|
||||||
|
@ -293,15 +314,13 @@ send queries for the ``auth`` app to ``auth_db``::
|
||||||
return True
|
return True
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def allow_migrate(self, db, model, **hints):
|
def allow_migrate(self, db, app_label, model, **hints):
|
||||||
"""
|
"""
|
||||||
Make sure the auth app only appears in the 'auth_db'
|
Make sure the auth app only appears in the 'auth_db'
|
||||||
database.
|
database.
|
||||||
"""
|
"""
|
||||||
if db == 'auth_db':
|
if app_label == 'auth':
|
||||||
return model._meta.app_label == 'auth'
|
return db == 'auth_db'
|
||||||
elif model._meta.app_label == 'auth':
|
|
||||||
return False
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
And we also want a router that sends all other apps to the
|
And we also want a router that sends all other apps to the
|
||||||
|
@ -333,7 +352,7 @@ from::
|
||||||
return True
|
return True
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def allow_migrate(self, db, model, **hints):
|
def allow_migrate(self, db, app_label, model, **hints):
|
||||||
"""
|
"""
|
||||||
All non-auth models end up in this pool.
|
All non-auth models end up in this pool.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -956,14 +956,17 @@ class DBCacheRouter(object):
|
||||||
def db_for_read(self, model, **hints):
|
def db_for_read(self, model, **hints):
|
||||||
if model._meta.app_label == 'django_cache':
|
if model._meta.app_label == 'django_cache':
|
||||||
return 'other'
|
return 'other'
|
||||||
|
return None
|
||||||
|
|
||||||
def db_for_write(self, model, **hints):
|
def db_for_write(self, model, **hints):
|
||||||
if model._meta.app_label == 'django_cache':
|
if model._meta.app_label == 'django_cache':
|
||||||
return 'other'
|
return 'other'
|
||||||
|
return None
|
||||||
|
|
||||||
def allow_migrate(self, db, model):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
if model._meta.app_label == 'django_cache':
|
if app_label == 'django_cache':
|
||||||
return db == 'other'
|
return db == 'other'
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@override_settings(
|
@override_settings(
|
||||||
|
|
|
@ -322,7 +322,7 @@ class OtherRouter(object):
|
||||||
def allow_relation(self, obj1, obj2, **hints):
|
def allow_relation(self, obj1, obj2, **hints):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def allow_migrate(self, db, model):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ class AgnosticRouter(object):
|
||||||
"""
|
"""
|
||||||
A router that doesn't have an opinion regarding migrating.
|
A router that doesn't have an opinion regarding migrating.
|
||||||
"""
|
"""
|
||||||
def allow_migrate(self, db, model, **hints):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ class MigrateNothingRouter(object):
|
||||||
"""
|
"""
|
||||||
A router that doesn't allow migrating.
|
A router that doesn't allow migrating.
|
||||||
"""
|
"""
|
||||||
def allow_migrate(self, db, model, **hints):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ class MigrateEverythingRouter(object):
|
||||||
"""
|
"""
|
||||||
A router that always allows migrating.
|
A router that always allows migrating.
|
||||||
"""
|
"""
|
||||||
def allow_migrate(self, db, model, **hints):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class MigrateWhenFooRouter(object):
|
||||||
"""
|
"""
|
||||||
A router that allows migrating depending on a hint.
|
A router that allows migrating depending on a hint.
|
||||||
"""
|
"""
|
||||||
def allow_migrate(self, db, model, **hints):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
return hints.get('foo', False)
|
return hints.get('foo', False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,11 @@ from django.db import DEFAULT_DB_ALIAS
|
||||||
|
|
||||||
|
|
||||||
class TestRouter(object):
|
class TestRouter(object):
|
||||||
# A test router. The behavior is vaguely primary/replica, but the
|
"""
|
||||||
# databases aren't assumed to propagate changes.
|
Vaguely behave like primary/replica, but the databases aren't assumed to
|
||||||
|
propagate changes.
|
||||||
|
"""
|
||||||
|
|
||||||
def db_for_read(self, model, instance=None, **hints):
|
def db_for_read(self, model, instance=None, **hints):
|
||||||
if instance:
|
if instance:
|
||||||
return instance._state.db or 'other'
|
return instance._state.db or 'other'
|
||||||
|
@ -17,13 +20,14 @@ class TestRouter(object):
|
||||||
def allow_relation(self, obj1, obj2, **hints):
|
def allow_relation(self, obj1, obj2, **hints):
|
||||||
return obj1._state.db in ('default', 'other') and obj2._state.db in ('default', 'other')
|
return obj1._state.db in ('default', 'other') and obj2._state.db in ('default', 'other')
|
||||||
|
|
||||||
def allow_migrate(self, db, model):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class AuthRouter(object):
|
class AuthRouter(object):
|
||||||
"""A router to control all database operations on models in
|
"""
|
||||||
the contrib.auth application"""
|
Control all database operations on models in the contrib.auth application.
|
||||||
|
"""
|
||||||
|
|
||||||
def db_for_read(self, model, **hints):
|
def db_for_read(self, model, **hints):
|
||||||
"Point all read operations on auth models to 'default'"
|
"Point all read operations on auth models to 'default'"
|
||||||
|
@ -45,12 +49,10 @@ class AuthRouter(object):
|
||||||
return True
|
return True
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def allow_migrate(self, db, model):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
"Make sure the auth app only appears on the 'other' db"
|
"Make sure the auth app only appears on the 'other' db"
|
||||||
if db == 'other':
|
if app_label == 'auth':
|
||||||
return model._meta.app_label == 'auth'
|
return db == 'other'
|
||||||
elif model._meta.app_label == 'auth':
|
|
||||||
return False
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import pickle
|
import pickle
|
||||||
|
import warnings
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
@ -11,6 +12,7 @@ from django.db import DEFAULT_DB_ALIAS, connections, router, transaction
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
from django.db.utils import ConnectionRouter
|
from django.db.utils import ConnectionRouter
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
|
from django.utils.encoding import force_text
|
||||||
from django.utils.six import StringIO
|
from django.utils.six import StringIO
|
||||||
|
|
||||||
from .models import Book, Person, Pet, Review, UserProfile
|
from .models import Book, Person, Pet, Review, UserProfile
|
||||||
|
@ -901,28 +903,58 @@ class RouterTestCase(TestCase):
|
||||||
def test_migrate_selection(self):
|
def test_migrate_selection(self):
|
||||||
"Synchronization behavior is predictable"
|
"Synchronization behavior is predictable"
|
||||||
|
|
||||||
self.assertTrue(router.allow_migrate('default', User))
|
self.assertTrue(router.allow_migrate_model('default', User))
|
||||||
self.assertTrue(router.allow_migrate('default', Book))
|
self.assertTrue(router.allow_migrate_model('default', Book))
|
||||||
|
|
||||||
self.assertTrue(router.allow_migrate('other', User))
|
self.assertTrue(router.allow_migrate_model('other', User))
|
||||||
self.assertTrue(router.allow_migrate('other', Book))
|
self.assertTrue(router.allow_migrate_model('other', Book))
|
||||||
|
|
||||||
with override_settings(DATABASE_ROUTERS=[TestRouter(), AuthRouter()]):
|
with override_settings(DATABASE_ROUTERS=[TestRouter(), AuthRouter()]):
|
||||||
# Add the auth router to the chain. TestRouter is a universal
|
# Add the auth router to the chain. TestRouter is a universal
|
||||||
# synchronizer, so it should have no effect.
|
# synchronizer, so it should have no effect.
|
||||||
self.assertTrue(router.allow_migrate('default', User))
|
self.assertTrue(router.allow_migrate_model('default', User))
|
||||||
self.assertTrue(router.allow_migrate('default', Book))
|
self.assertTrue(router.allow_migrate_model('default', Book))
|
||||||
|
|
||||||
self.assertTrue(router.allow_migrate('other', User))
|
self.assertTrue(router.allow_migrate_model('other', User))
|
||||||
self.assertTrue(router.allow_migrate('other', Book))
|
self.assertTrue(router.allow_migrate_model('other', Book))
|
||||||
|
|
||||||
with override_settings(DATABASE_ROUTERS=[AuthRouter(), TestRouter()]):
|
with override_settings(DATABASE_ROUTERS=[AuthRouter(), TestRouter()]):
|
||||||
# Now check what happens if the router order is reversed.
|
# Now check what happens if the router order is reversed.
|
||||||
self.assertFalse(router.allow_migrate('default', User))
|
self.assertFalse(router.allow_migrate_model('default', User))
|
||||||
self.assertTrue(router.allow_migrate('default', Book))
|
self.assertTrue(router.allow_migrate_model('default', Book))
|
||||||
|
|
||||||
self.assertTrue(router.allow_migrate('other', User))
|
self.assertTrue(router.allow_migrate_model('other', User))
|
||||||
self.assertFalse(router.allow_migrate('other', Book))
|
self.assertTrue(router.allow_migrate_model('other', Book))
|
||||||
|
|
||||||
|
def test_migrate_legacy_router(self):
|
||||||
|
class LegacyRouter(object):
|
||||||
|
def allow_migrate(self, db, model):
|
||||||
|
"""
|
||||||
|
Deprecated allow_migrate signature should trigger
|
||||||
|
RemovedInDjango20Warning.
|
||||||
|
"""
|
||||||
|
assert db == 'default'
|
||||||
|
assert model is User
|
||||||
|
return True
|
||||||
|
|
||||||
|
with override_settings(DATABASE_ROUTERS=[LegacyRouter()]):
|
||||||
|
with warnings.catch_warnings(record=True) as recorded:
|
||||||
|
warnings.filterwarnings('always')
|
||||||
|
|
||||||
|
msg = (
|
||||||
|
"The signature of allow_migrate has changed from "
|
||||||
|
"allow_migrate(self, db, model) to "
|
||||||
|
"allow_migrate(self, db, app_label, model_name=None, **hints). "
|
||||||
|
"Support for the old signature will be removed in Django 2.0."
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertTrue(router.allow_migrate_model('default', User))
|
||||||
|
self.assertEqual(force_text(recorded.pop().message), msg)
|
||||||
|
|
||||||
|
self.assertEqual(recorded, [])
|
||||||
|
|
||||||
|
self.assertTrue(router.allow_migrate('default', 'app_label'))
|
||||||
|
self.assertEqual(force_text(recorded.pop().message), msg)
|
||||||
|
|
||||||
def test_partial_router(self):
|
def test_partial_router(self):
|
||||||
"A router can choose to implement a subset of methods"
|
"A router can choose to implement a subset of methods"
|
||||||
|
@ -939,8 +971,8 @@ class RouterTestCase(TestCase):
|
||||||
|
|
||||||
self.assertTrue(router.allow_relation(dive, dive))
|
self.assertTrue(router.allow_relation(dive, dive))
|
||||||
|
|
||||||
self.assertTrue(router.allow_migrate('default', User))
|
self.assertTrue(router.allow_migrate_model('default', User))
|
||||||
self.assertTrue(router.allow_migrate('default', Book))
|
self.assertTrue(router.allow_migrate_model('default', Book))
|
||||||
|
|
||||||
with override_settings(DATABASE_ROUTERS=[WriteRouter(), AuthRouter(), TestRouter()]):
|
with override_settings(DATABASE_ROUTERS=[WriteRouter(), AuthRouter(), TestRouter()]):
|
||||||
self.assertEqual(router.db_for_read(User), 'default')
|
self.assertEqual(router.db_for_read(User), 'default')
|
||||||
|
@ -951,8 +983,8 @@ class RouterTestCase(TestCase):
|
||||||
|
|
||||||
self.assertTrue(router.allow_relation(dive, dive))
|
self.assertTrue(router.allow_relation(dive, dive))
|
||||||
|
|
||||||
self.assertFalse(router.allow_migrate('default', User))
|
self.assertFalse(router.allow_migrate_model('default', User))
|
||||||
self.assertTrue(router.allow_migrate('default', Book))
|
self.assertTrue(router.allow_migrate_model('default', Book))
|
||||||
|
|
||||||
def test_database_routing(self):
|
def test_database_routing(self):
|
||||||
marty = Person.objects.using('default').create(name="Marty Alchin")
|
marty = Person.objects.using('default').create(name="Marty Alchin")
|
||||||
|
@ -1492,11 +1524,11 @@ class AntiPetRouter(object):
|
||||||
# A router that only expresses an opinion on migrate,
|
# A router that only expresses an opinion on migrate,
|
||||||
# passing pets to the 'other' database
|
# passing pets to the 'other' database
|
||||||
|
|
||||||
def allow_migrate(self, db, model):
|
def allow_migrate(self, db, app_label, model_name, **hints):
|
||||||
if db == 'other':
|
if db == 'other':
|
||||||
return model._meta.object_name == 'Pet'
|
return model_name == 'pet'
|
||||||
else:
|
else:
|
||||||
return model._meta.object_name != 'Pet'
|
return model_name != 'pet'
|
||||||
|
|
||||||
|
|
||||||
class FixtureTestCase(TestCase):
|
class FixtureTestCase(TestCase):
|
||||||
|
@ -1757,7 +1789,7 @@ class RouterModelArgumentTestCase(TestCase):
|
||||||
|
|
||||||
|
|
||||||
class SyncOnlyDefaultDatabaseRouter(object):
|
class SyncOnlyDefaultDatabaseRouter(object):
|
||||||
def allow_migrate(self, db, model):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
return db == DEFAULT_DB_ALIAS
|
return db == DEFAULT_DB_ALIAS
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ class SitesFrameworkTests(TestCase):
|
||||||
|
|
||||||
|
|
||||||
class JustOtherRouter(object):
|
class JustOtherRouter(object):
|
||||||
def allow_migrate(self, db, model):
|
def allow_migrate(self, db, app_label, **hints):
|
||||||
return db == 'other'
|
return db == 'other'
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue