parent
4ee06ec3fc
commit
a159b1facd
|
@ -108,8 +108,8 @@ class MigrationAutodetector(object):
|
||||||
|
|
||||||
# Prepare some old/new state and model lists, separating
|
# Prepare some old/new state and model lists, separating
|
||||||
# proxy models and ignoring unmigrated apps.
|
# proxy models and ignoring unmigrated apps.
|
||||||
self.old_apps = self.from_state.render(ignore_swappable=True)
|
self.old_apps = self.from_state.apps
|
||||||
self.new_apps = self.to_state.render()
|
self.new_apps = self.to_state.apps
|
||||||
self.old_model_keys = []
|
self.old_model_keys = []
|
||||||
self.old_proxy_keys = []
|
self.old_proxy_keys = []
|
||||||
self.old_unmanaged_keys = []
|
self.old_unmanaged_keys = []
|
||||||
|
|
|
@ -137,7 +137,7 @@ class MigrationExecutor(object):
|
||||||
on initial migrations (as it only looks for CreateModel).
|
on initial migrations (as it only looks for CreateModel).
|
||||||
"""
|
"""
|
||||||
project_state = self.loader.project_state((migration.app_label, migration.name), at_end=True)
|
project_state = self.loader.project_state((migration.app_label, migration.name), at_end=True)
|
||||||
apps = project_state.render()
|
apps = project_state.apps
|
||||||
found_create_migration = False
|
found_create_migration = False
|
||||||
# Bail if the migration isn't the first one in its app
|
# Bail if the migration isn't the first one in its app
|
||||||
if [name for app, name in migration.dependencies if app == migration.app_label]:
|
if [name for app, name in migration.dependencies if app == migration.app_label]:
|
||||||
|
|
|
@ -40,9 +40,9 @@ class AddField(Operation):
|
||||||
state.models[app_label, self.model_name.lower()].fields.append((self.name, field))
|
state.models[app_label, self.model_name.lower()].fields.append((self.name, field))
|
||||||
|
|
||||||
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.render().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.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.render().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_by_name(self.name)[0]
|
field = to_model._meta.get_field_by_name(self.name)[0]
|
||||||
if not self.preserve_default:
|
if not self.preserve_default:
|
||||||
field.default = self.field.default
|
field.default = self.field.default
|
||||||
|
@ -54,7 +54,7 @@ class AddField(Operation):
|
||||||
field.default = NOT_PROVIDED
|
field.default = NOT_PROVIDED
|
||||||
|
|
||||||
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.render().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.allowed_to_migrate(schema_editor.connection.alias, from_model):
|
||||||
schema_editor.remove_field(from_model, from_model._meta.get_field_by_name(self.name)[0])
|
schema_editor.remove_field(from_model, from_model._meta.get_field_by_name(self.name)[0])
|
||||||
|
|
||||||
|
@ -96,14 +96,14 @@ class RemoveField(Operation):
|
||||||
state.models[app_label, self.model_name.lower()].fields = new_fields
|
state.models[app_label, self.model_name.lower()].fields = new_fields
|
||||||
|
|
||||||
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.render().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.allowed_to_migrate(schema_editor.connection.alias, from_model):
|
||||||
schema_editor.remove_field(from_model, from_model._meta.get_field_by_name(self.name)[0])
|
schema_editor.remove_field(from_model, from_model._meta.get_field_by_name(self.name)[0])
|
||||||
|
|
||||||
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.render().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.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.render().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_by_name(self.name)[0])
|
schema_editor.add_field(from_model, to_model._meta.get_field_by_name(self.name)[0])
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
|
@ -152,9 +152,9 @@ 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.render().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.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.render().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_by_name(self.name)[0]
|
from_field = from_model._meta.get_field_by_name(self.name)[0]
|
||||||
to_field = to_model._meta.get_field_by_name(self.name)[0]
|
to_field = to_model._meta.get_field_by_name(self.name)[0]
|
||||||
# If the field is a relatedfield with an unresolved rel.to, just
|
# If the field is a relatedfield with an unresolved rel.to, just
|
||||||
|
@ -222,9 +222,9 @@ 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.render().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.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.render().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,
|
||||||
from_model._meta.get_field_by_name(self.old_name)[0],
|
from_model._meta.get_field_by_name(self.old_name)[0],
|
||||||
|
@ -232,9 +232,9 @@ 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.render().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.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.render().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,
|
||||||
from_model._meta.get_field_by_name(self.new_name)[0],
|
from_model._meta.get_field_by_name(self.new_name)[0],
|
||||||
|
|
|
@ -49,14 +49,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):
|
||||||
apps = to_state.render()
|
model = to_state.apps.get_model(app_label, self.name)
|
||||||
model = apps.get_model(app_label, self.name)
|
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, model):
|
if self.allowed_to_migrate(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):
|
||||||
apps = from_state.render()
|
model = from_state.apps.get_model(app_label, self.name)
|
||||||
model = apps.get_model(app_label, self.name)
|
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, model):
|
if self.allowed_to_migrate(schema_editor.connection.alias, model):
|
||||||
schema_editor.delete_model(model)
|
schema_editor.delete_model(model)
|
||||||
|
|
||||||
|
@ -103,14 +101,12 @@ class DeleteModel(Operation):
|
||||||
del state.models[app_label, self.name.lower()]
|
del state.models[app_label, self.name.lower()]
|
||||||
|
|
||||||
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
apps = from_state.render()
|
model = from_state.apps.get_model(app_label, self.name)
|
||||||
model = apps.get_model(app_label, self.name)
|
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, model):
|
if self.allowed_to_migrate(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):
|
||||||
apps = to_state.render()
|
model = to_state.apps.get_model(app_label, self.name)
|
||||||
model = apps.get_model(app_label, self.name)
|
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, model):
|
if self.allowed_to_migrate(schema_editor.connection.alias, model):
|
||||||
schema_editor.create_model(model)
|
schema_editor.create_model(model)
|
||||||
|
|
||||||
|
@ -143,7 +139,7 @@ class RenameModel(Operation):
|
||||||
|
|
||||||
def state_forwards(self, app_label, state):
|
def state_forwards(self, app_label, state):
|
||||||
# Get all of the related objects we need to repoint
|
# Get all of the related objects we need to repoint
|
||||||
apps = state.render(skip_cache=True)
|
apps = state.apps
|
||||||
model = apps.get_model(app_label, self.old_name)
|
model = apps.get_model(app_label, self.old_name)
|
||||||
related_objects = model._meta.get_all_related_objects()
|
related_objects = model._meta.get_all_related_objects()
|
||||||
related_m2m_objects = model._meta.get_all_related_many_to_many_objects()
|
related_m2m_objects = model._meta.get_all_related_many_to_many_objects()
|
||||||
|
@ -168,13 +164,12 @@ class RenameModel(Operation):
|
||||||
field.rel.to = "%s.%s" % (app_label, self.new_name)
|
field.rel.to = "%s.%s" % (app_label, self.new_name)
|
||||||
new_fields.append((name, field))
|
new_fields.append((name, field))
|
||||||
state.models[related_key].fields = new_fields
|
state.models[related_key].fields = new_fields
|
||||||
|
del state.apps # FIXME: this should be replaced by a logic in state (update_model?)
|
||||||
|
|
||||||
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_apps = to_state.render()
|
new_model = to_state.apps.get_model(app_label, self.new_name)
|
||||||
new_model = new_apps.get_model(app_label, self.new_name)
|
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
||||||
old_apps = from_state.render()
|
old_model = from_state.apps.get_model(app_label, self.old_name)
|
||||||
old_model = old_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(
|
||||||
new_model,
|
new_model,
|
||||||
|
@ -194,7 +189,7 @@ class RenameModel(Operation):
|
||||||
related_object.model._meta.app_label,
|
related_object.model._meta.app_label,
|
||||||
related_object.model._meta.object_name.lower(),
|
related_object.model._meta.object_name.lower(),
|
||||||
)
|
)
|
||||||
to_field = new_apps.get_model(
|
to_field = to_state.apps.get_model(
|
||||||
*related_key
|
*related_key
|
||||||
)._meta.get_field_by_name(related_object.field.name)[0]
|
)._meta.get_field_by_name(related_object.field.name)[0]
|
||||||
schema_editor.alter_field(
|
schema_editor.alter_field(
|
||||||
|
@ -242,11 +237,9 @@ class AlterModelTable(Operation):
|
||||||
state.models[app_label, self.name.lower()].options["db_table"] = self.table
|
state.models[app_label, self.name.lower()].options["db_table"] = self.table
|
||||||
|
|
||||||
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_apps = to_state.render()
|
new_model = to_state.apps.get_model(app_label, self.name)
|
||||||
new_model = new_apps.get_model(app_label, self.name)
|
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
||||||
old_apps = from_state.render()
|
old_model = from_state.apps.get_model(app_label, self.name)
|
||||||
old_model = old_apps.get_model(app_label, self.name)
|
|
||||||
schema_editor.alter_db_table(
|
schema_editor.alter_db_table(
|
||||||
new_model,
|
new_model,
|
||||||
old_model._meta.db_table,
|
old_model._meta.db_table,
|
||||||
|
@ -299,11 +292,9 @@ class AlterUniqueTogether(Operation):
|
||||||
model_state.options[self.option_name] = self.unique_together
|
model_state.options[self.option_name] = self.unique_together
|
||||||
|
|
||||||
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_apps = to_state.render()
|
new_model = to_state.apps.get_model(app_label, self.name)
|
||||||
new_model = new_apps.get_model(app_label, self.name)
|
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
||||||
old_apps = from_state.render()
|
old_model = from_state.apps.get_model(app_label, self.name)
|
||||||
old_model = old_apps.get_model(app_label, self.name)
|
|
||||||
schema_editor.alter_unique_together(
|
schema_editor.alter_unique_together(
|
||||||
new_model,
|
new_model,
|
||||||
getattr(old_model._meta, self.option_name, set()),
|
getattr(old_model._meta, self.option_name, set()),
|
||||||
|
@ -348,11 +339,9 @@ class AlterIndexTogether(Operation):
|
||||||
model_state.options[self.option_name] = self.index_together
|
model_state.options[self.option_name] = self.index_together
|
||||||
|
|
||||||
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_apps = to_state.render()
|
new_model = to_state.apps.get_model(app_label, self.name)
|
||||||
new_model = new_apps.get_model(app_label, self.name)
|
|
||||||
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
|
||||||
old_apps = from_state.render()
|
old_model = from_state.apps.get_model(app_label, self.name)
|
||||||
old_model = old_apps.get_model(app_label, self.name)
|
|
||||||
schema_editor.alter_index_together(
|
schema_editor.alter_index_together(
|
||||||
new_model,
|
new_model,
|
||||||
getattr(old_model._meta, self.option_name, set()),
|
getattr(old_model._meta, self.option_name, set()),
|
||||||
|
@ -394,9 +383,9 @@ class AlterOrderWithRespectTo(Operation):
|
||||||
model_state.options['order_with_respect_to'] = self.order_with_respect_to
|
model_state.options['order_with_respect_to'] = self.order_with_respect_to
|
||||||
|
|
||||||
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.render().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.allowed_to_migrate(schema_editor.connection.alias, to_model):
|
||||||
from_model = from_state.render().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:
|
||||||
schema_editor.remove_field(from_model, from_model._meta.get_field_by_name("_order")[0])
|
schema_editor.remove_field(from_model, from_model._meta.get_field_by_name("_order")[0])
|
||||||
|
|
|
@ -166,12 +166,12 @@ class RunPython(Operation):
|
||||||
# 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
|
||||||
# use direct imports, so we go with a documentation approach instead.
|
# use direct imports, so we go with a documentation approach instead.
|
||||||
self.code(from_state.render(), schema_editor)
|
self.code(from_state.apps, schema_editor)
|
||||||
|
|
||||||
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")
|
||||||
self.reverse_code(from_state.render(), schema_editor)
|
self.reverse_code(from_state.apps, schema_editor)
|
||||||
|
|
||||||
def describe(self):
|
def describe(self):
|
||||||
return "Raw Python operation"
|
return "Raw Python operation"
|
||||||
|
|
|
@ -9,6 +9,7 @@ from django.db.models.fields.proxy import OrderWrt
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import force_text, smart_text
|
from django.utils.encoding import force_text, smart_text
|
||||||
|
from django.utils.functional import cached_property
|
||||||
from django.utils.module_loading import import_string
|
from django.utils.module_loading import import_string
|
||||||
from django.utils.version import get_docs_version
|
from django.utils.version import get_docs_version
|
||||||
|
|
||||||
|
@ -26,7 +27,6 @@ class ProjectState(object):
|
||||||
|
|
||||||
def __init__(self, models=None, real_apps=None):
|
def __init__(self, models=None, real_apps=None):
|
||||||
self.models = models or {}
|
self.models = models or {}
|
||||||
self.apps = None
|
|
||||||
# Apps to include from main registry, usually unmigrated ones
|
# Apps to include from main registry, usually unmigrated ones
|
||||||
self.real_apps = real_apps or []
|
self.real_apps = real_apps or []
|
||||||
|
|
||||||
|
@ -40,66 +40,9 @@ class ProjectState(object):
|
||||||
real_apps=self.real_apps,
|
real_apps=self.real_apps,
|
||||||
)
|
)
|
||||||
|
|
||||||
def render(self, include_real=None, ignore_swappable=False, skip_cache=False):
|
@cached_property
|
||||||
"Turns the project state into actual models in a new Apps"
|
def apps(self):
|
||||||
if self.apps is None or skip_cache:
|
return StateApps(self.real_apps, self.models)
|
||||||
# Any apps in self.real_apps should have all their models included
|
|
||||||
# in the render. We don't use the original model instances as there
|
|
||||||
# are some variables that refer to the Apps object.
|
|
||||||
# FKs/M2Ms from real apps are also not included as they just
|
|
||||||
# mess things up with partial states (due to lack of dependencies)
|
|
||||||
real_models = []
|
|
||||||
for app_label in self.real_apps:
|
|
||||||
app = global_apps.get_app_config(app_label)
|
|
||||||
for model in app.get_models():
|
|
||||||
real_models.append(ModelState.from_model(model, exclude_rels=True))
|
|
||||||
# Populate the app registry with a stub for each application.
|
|
||||||
app_labels = set(model_state.app_label for model_state in self.models.values())
|
|
||||||
self.apps = Apps([AppConfigStub(label) for label in sorted(self.real_apps + list(app_labels))])
|
|
||||||
# We keep trying to render the models in a loop, ignoring invalid
|
|
||||||
# base errors, until the size of the unrendered models doesn't
|
|
||||||
# decrease by at least one, meaning there's a base dependency loop/
|
|
||||||
# missing base.
|
|
||||||
unrendered_models = list(self.models.values()) + real_models
|
|
||||||
while unrendered_models:
|
|
||||||
new_unrendered_models = []
|
|
||||||
for model in unrendered_models:
|
|
||||||
try:
|
|
||||||
model.render(self.apps)
|
|
||||||
except InvalidBasesError:
|
|
||||||
new_unrendered_models.append(model)
|
|
||||||
if len(new_unrendered_models) == len(unrendered_models):
|
|
||||||
raise InvalidBasesError(
|
|
||||||
"Cannot resolve bases for %r\nThis can happen if you are inheriting models from an "
|
|
||||||
"app with migrations (e.g. contrib.auth)\n in an app with no migrations; see "
|
|
||||||
"https://docs.djangoproject.com/en/%s/topics/migrations/#dependencies "
|
|
||||||
"for more" % (new_unrendered_models, get_docs_version())
|
|
||||||
)
|
|
||||||
unrendered_models = new_unrendered_models
|
|
||||||
# make sure apps has no dangling references
|
|
||||||
if self.apps._pending_lookups:
|
|
||||||
# There's some lookups left. See if we can first resolve them
|
|
||||||
# ourselves - sometimes fields are added after class_prepared is sent
|
|
||||||
for lookup_model, operations in self.apps._pending_lookups.items():
|
|
||||||
try:
|
|
||||||
model = self.apps.get_model(lookup_model[0], lookup_model[1])
|
|
||||||
except LookupError:
|
|
||||||
app_label = "%s.%s" % (lookup_model[0], lookup_model[1])
|
|
||||||
if app_label == settings.AUTH_USER_MODEL and ignore_swappable:
|
|
||||||
continue
|
|
||||||
# Raise an error with a best-effort helpful message
|
|
||||||
# (only for the first issue). Error message should look like:
|
|
||||||
# "ValueError: Lookup failed for model referenced by
|
|
||||||
# field migrations.Book.author: migrations.Author"
|
|
||||||
msg = "Lookup failed for model referenced by field {field}: {model[0]}.{model[1]}"
|
|
||||||
raise ValueError(msg.format(field=operations[0][1], model=lookup_model))
|
|
||||||
else:
|
|
||||||
do_pending_lookups(model)
|
|
||||||
try:
|
|
||||||
return self.apps
|
|
||||||
finally:
|
|
||||||
if skip_cache:
|
|
||||||
self.apps = None
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_apps(cls, apps):
|
def from_apps(cls, apps):
|
||||||
|
@ -139,6 +82,67 @@ class AppConfigStub(AppConfig):
|
||||||
self.models = all_models
|
self.models = all_models
|
||||||
|
|
||||||
|
|
||||||
|
class StateApps(Apps):
|
||||||
|
"""
|
||||||
|
Subclass of the global Apps registry class to better handle dynamic model
|
||||||
|
additions and removals.
|
||||||
|
"""
|
||||||
|
def __init__(self, real_apps, models):
|
||||||
|
# Any apps in self.real_apps should have all their models included
|
||||||
|
# in the render. We don't use the original model instances as there
|
||||||
|
# are some variables that refer to the Apps object.
|
||||||
|
# FKs/M2Ms from real apps are also not included as they just
|
||||||
|
# mess things up with partial states (due to lack of dependencies)
|
||||||
|
real_models = []
|
||||||
|
for app_label in real_apps:
|
||||||
|
app = global_apps.get_app_config(app_label)
|
||||||
|
for model in app.get_models():
|
||||||
|
real_models.append(ModelState.from_model(model, exclude_rels=True))
|
||||||
|
# Populate the app registry with a stub for each application.
|
||||||
|
app_labels = {model_state.app_label for model_state in models.values()}
|
||||||
|
app_configs = [AppConfigStub(label) for label in sorted(real_apps + list(app_labels))]
|
||||||
|
super(StateApps, self).__init__(app_configs)
|
||||||
|
|
||||||
|
# We keep trying to render the models in a loop, ignoring invalid
|
||||||
|
# base errors, until the size of the unrendered models doesn't
|
||||||
|
# decrease by at least one, meaning there's a base dependency loop/
|
||||||
|
# missing base.
|
||||||
|
unrendered_models = list(models.values()) + real_models
|
||||||
|
while unrendered_models:
|
||||||
|
new_unrendered_models = []
|
||||||
|
for model in unrendered_models:
|
||||||
|
try:
|
||||||
|
model.render(self)
|
||||||
|
except InvalidBasesError:
|
||||||
|
new_unrendered_models.append(model)
|
||||||
|
if len(new_unrendered_models) == len(unrendered_models):
|
||||||
|
raise InvalidBasesError(
|
||||||
|
"Cannot resolve bases for %r\nThis can happen if you are inheriting models from an "
|
||||||
|
"app with migrations (e.g. contrib.auth)\n in an app with no migrations; see "
|
||||||
|
"https://docs.djangoproject.com/en/%s/topics/migrations/#dependencies "
|
||||||
|
"for more" % (new_unrendered_models, get_docs_version())
|
||||||
|
)
|
||||||
|
unrendered_models = new_unrendered_models
|
||||||
|
|
||||||
|
# If there are some lookups left, see if we can first resolve them
|
||||||
|
# ourselves - sometimes fields are added after class_prepared is sent
|
||||||
|
for lookup_model, operations in self._pending_lookups.items():
|
||||||
|
try:
|
||||||
|
model = self.get_model(lookup_model[0], lookup_model[1])
|
||||||
|
except LookupError:
|
||||||
|
app_label = "%s.%s" % (lookup_model[0], lookup_model[1])
|
||||||
|
if app_label == settings.AUTH_USER_MODEL and ignore_swappable:
|
||||||
|
continue
|
||||||
|
# Raise an error with a best-effort helpful message
|
||||||
|
# (only for the first issue). Error message should look like:
|
||||||
|
# "ValueError: Lookup failed for model referenced by
|
||||||
|
# field migrations.Book.author: migrations.Author"
|
||||||
|
msg = "Lookup failed for model referenced by field {field}: {model[0]}.{model[1]}"
|
||||||
|
raise ValueError(msg.format(field=operations[0][1], model=lookup_model))
|
||||||
|
else:
|
||||||
|
do_pending_lookups(model)
|
||||||
|
|
||||||
|
|
||||||
class ModelState(object):
|
class ModelState(object):
|
||||||
"""
|
"""
|
||||||
Represents a Django Model. We don't use the actual Model class
|
Represents a Django Model. We don't use the actual Model class
|
||||||
|
|
|
@ -219,7 +219,7 @@ class ExecutorTests(MigrationTestBase):
|
||||||
# exists in the global app registry temporarily.
|
# exists in the global app registry temporarily.
|
||||||
old_table_names = connection.introspection.table_names
|
old_table_names = connection.introspection.table_names
|
||||||
connection.introspection.table_names = lambda c: [x for x in old_table_names(c) if x != "auth_user"]
|
connection.introspection.table_names = lambda c: [x for x in old_table_names(c) if x != "auth_user"]
|
||||||
migrations_apps = executor.loader.project_state(("migrations", "0001_initial")).render()
|
migrations_apps = executor.loader.project_state(("migrations", "0001_initial")).apps
|
||||||
global_apps.get_app_config("migrations").models["author"] = migrations_apps.get_model("migrations", "author")
|
global_apps.get_app_config("migrations").models["author"] = migrations_apps.get_model("migrations", "author")
|
||||||
try:
|
try:
|
||||||
migration = executor.loader.get_migration("auth", "0001_initial")
|
migration = executor.loader.get_migration("auth", "0001_initial")
|
||||||
|
|
|
@ -267,9 +267,8 @@ class OperationTests(OperationTestBase):
|
||||||
self.assertColumnNotExists("test_crmomm_stable", "ponies")
|
self.assertColumnNotExists("test_crmomm_stable", "ponies")
|
||||||
# Make sure the M2M field actually works
|
# Make sure the M2M field actually works
|
||||||
with atomic():
|
with atomic():
|
||||||
new_apps = new_state.render()
|
Pony = new_state.apps.get_model("test_crmomm", "Pony")
|
||||||
Pony = new_apps.get_model("test_crmomm", "Pony")
|
Stable = new_state.apps.get_model("test_crmomm", "Stable")
|
||||||
Stable = new_apps.get_model("test_crmomm", "Stable")
|
|
||||||
stable = Stable.objects.create()
|
stable = Stable.objects.create()
|
||||||
p1 = Pony.objects.create(pink=False, weight=4.55)
|
p1 = Pony.objects.create(pink=False, weight=4.55)
|
||||||
p2 = Pony.objects.create(pink=True, weight=5.43)
|
p2 = Pony.objects.create(pink=True, weight=5.43)
|
||||||
|
@ -545,8 +544,7 @@ class OperationTests(OperationTestBase):
|
||||||
project_state = self.apply_operations(app_label, project_state, operations=[
|
project_state = self.apply_operations(app_label, project_state, operations=[
|
||||||
migrations.RenameModel("ReflexivePony", "ReflexivePony2"),
|
migrations.RenameModel("ReflexivePony", "ReflexivePony2"),
|
||||||
])
|
])
|
||||||
apps = project_state.render()
|
Pony = project_state.apps.get_model(app_label, "ReflexivePony2")
|
||||||
Pony = apps.get_model(app_label, "ReflexivePony2")
|
|
||||||
pony = Pony.objects.create()
|
pony = Pony.objects.create()
|
||||||
pony.ponies.add(pony)
|
pony.ponies.add(pony)
|
||||||
|
|
||||||
|
@ -589,8 +587,7 @@ class OperationTests(OperationTestBase):
|
||||||
"""
|
"""
|
||||||
project_state = self.set_up_test_model("test_adchfl")
|
project_state = self.set_up_test_model("test_adchfl")
|
||||||
|
|
||||||
new_apps = project_state.render()
|
Pony = project_state.apps.get_model("test_adchfl", "Pony")
|
||||||
Pony = new_apps.get_model("test_adchfl", "Pony")
|
|
||||||
pony = Pony.objects.create(weight=42)
|
pony = Pony.objects.create(weight=42)
|
||||||
|
|
||||||
new_state = self.apply_operations("test_adchfl", project_state, [
|
new_state = self.apply_operations("test_adchfl", project_state, [
|
||||||
|
@ -618,8 +615,7 @@ class OperationTests(OperationTestBase):
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
|
|
||||||
new_apps = new_state.render()
|
Pony = new_state.apps.get_model("test_adchfl", "Pony")
|
||||||
Pony = new_apps.get_model("test_adchfl", "Pony")
|
|
||||||
pony = Pony.objects.get(pk=pony.pk)
|
pony = Pony.objects.get(pk=pony.pk)
|
||||||
self.assertEqual(pony.text, "some text")
|
self.assertEqual(pony.text, "some text")
|
||||||
self.assertEqual(pony.empty, "")
|
self.assertEqual(pony.empty, "")
|
||||||
|
@ -632,8 +628,7 @@ class OperationTests(OperationTestBase):
|
||||||
"""
|
"""
|
||||||
project_state = self.set_up_test_model("test_adtxtfl")
|
project_state = self.set_up_test_model("test_adtxtfl")
|
||||||
|
|
||||||
new_apps = project_state.render()
|
Pony = project_state.apps.get_model("test_adtxtfl", "Pony")
|
||||||
Pony = new_apps.get_model("test_adtxtfl", "Pony")
|
|
||||||
pony = Pony.objects.create(weight=42)
|
pony = Pony.objects.create(weight=42)
|
||||||
|
|
||||||
new_state = self.apply_operations("test_adtxtfl", project_state, [
|
new_state = self.apply_operations("test_adtxtfl", project_state, [
|
||||||
|
@ -661,8 +656,7 @@ class OperationTests(OperationTestBase):
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
|
|
||||||
new_apps = new_state.render()
|
Pony = new_state.apps.get_model("test_adtxtfl", "Pony")
|
||||||
Pony = new_apps.get_model("test_adtxtfl", "Pony")
|
|
||||||
pony = Pony.objects.get(pk=pony.pk)
|
pony = Pony.objects.get(pk=pony.pk)
|
||||||
self.assertEqual(pony.text, "some text")
|
self.assertEqual(pony.text, "some text")
|
||||||
self.assertEqual(pony.empty, "")
|
self.assertEqual(pony.empty, "")
|
||||||
|
@ -676,8 +670,7 @@ class OperationTests(OperationTestBase):
|
||||||
"""
|
"""
|
||||||
project_state = self.set_up_test_model("test_adbinfl")
|
project_state = self.set_up_test_model("test_adbinfl")
|
||||||
|
|
||||||
new_apps = project_state.render()
|
Pony = project_state.apps.get_model("test_adbinfl", "Pony")
|
||||||
Pony = new_apps.get_model("test_adbinfl", "Pony")
|
|
||||||
pony = Pony.objects.create(weight=42)
|
pony = Pony.objects.create(weight=42)
|
||||||
|
|
||||||
new_state = self.apply_operations("test_adbinfl", project_state, [
|
new_state = self.apply_operations("test_adbinfl", project_state, [
|
||||||
|
@ -705,8 +698,7 @@ class OperationTests(OperationTestBase):
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
|
|
||||||
new_apps = new_state.render()
|
Pony = new_state.apps.get_model("test_adbinfl", "Pony")
|
||||||
Pony = new_apps.get_model("test_adbinfl", "Pony")
|
|
||||||
pony = Pony.objects.get(pk=pony.pk)
|
pony = Pony.objects.get(pk=pony.pk)
|
||||||
# SQLite returns buffer/memoryview, cast to bytes for checking.
|
# SQLite returns buffer/memoryview, cast to bytes for checking.
|
||||||
self.assertEqual(bytes(pony.blob), b"some text")
|
self.assertEqual(bytes(pony.blob), b"some text")
|
||||||
|
@ -753,7 +745,7 @@ class OperationTests(OperationTestBase):
|
||||||
][0]
|
][0]
|
||||||
self.assertEqual(field.default, NOT_PROVIDED)
|
self.assertEqual(field.default, NOT_PROVIDED)
|
||||||
# Test the database alteration
|
# Test the database alteration
|
||||||
project_state.render().get_model("test_adflpd", "pony").objects.create(
|
project_state.apps.get_model("test_adflpd", "pony").objects.create(
|
||||||
weight=4,
|
weight=4,
|
||||||
)
|
)
|
||||||
self.assertColumnNotExists("test_adflpd_pony", "height")
|
self.assertColumnNotExists("test_adflpd_pony", "height")
|
||||||
|
@ -784,8 +776,7 @@ class OperationTests(OperationTestBase):
|
||||||
self.assertColumnNotExists("test_adflmm_pony", "stables")
|
self.assertColumnNotExists("test_adflmm_pony", "stables")
|
||||||
# Make sure the M2M field actually works
|
# Make sure the M2M field actually works
|
||||||
with atomic():
|
with atomic():
|
||||||
new_apps = new_state.render()
|
Pony = new_state.apps.get_model("test_adflmm", "Pony")
|
||||||
Pony = new_apps.get_model("test_adflmm", "Pony")
|
|
||||||
p = Pony.objects.create(pink=False, weight=4.55)
|
p = Pony.objects.create(pink=False, weight=4.55)
|
||||||
p.stables.create()
|
p.stables.create()
|
||||||
self.assertEqual(p.stables.count(), 1)
|
self.assertEqual(p.stables.count(), 1)
|
||||||
|
@ -801,15 +792,13 @@ class OperationTests(OperationTestBase):
|
||||||
project_state = self.apply_operations("test_alflmm", project_state, operations=[
|
project_state = self.apply_operations("test_alflmm", project_state, operations=[
|
||||||
migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies"))
|
migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies"))
|
||||||
])
|
])
|
||||||
new_apps = project_state.render()
|
Pony = project_state.apps.get_model("test_alflmm", "Pony")
|
||||||
Pony = new_apps.get_model("test_alflmm", "Pony")
|
|
||||||
self.assertFalse(Pony._meta.get_field('stables').blank)
|
self.assertFalse(Pony._meta.get_field('stables').blank)
|
||||||
|
|
||||||
project_state = self.apply_operations("test_alflmm", project_state, operations=[
|
project_state = self.apply_operations("test_alflmm", project_state, operations=[
|
||||||
migrations.AlterField("Pony", "stables", models.ManyToManyField(to="Stable", related_name="ponies", blank=True))
|
migrations.AlterField("Pony", "stables", models.ManyToManyField(to="Stable", related_name="ponies", blank=True))
|
||||||
])
|
])
|
||||||
new_apps = project_state.render()
|
Pony = project_state.apps.get_model("test_alflmm", "Pony")
|
||||||
Pony = new_apps.get_model("test_alflmm", "Pony")
|
|
||||||
self.assertTrue(Pony._meta.get_field('stables').blank)
|
self.assertTrue(Pony._meta.get_field('stables').blank)
|
||||||
|
|
||||||
def test_repoint_field_m2m(self):
|
def test_repoint_field_m2m(self):
|
||||||
|
@ -818,16 +807,14 @@ class OperationTests(OperationTestBase):
|
||||||
project_state = self.apply_operations("test_alflmm", project_state, operations=[
|
project_state = self.apply_operations("test_alflmm", project_state, operations=[
|
||||||
migrations.AddField("Pony", "places", models.ManyToManyField("Stable", related_name="ponies"))
|
migrations.AddField("Pony", "places", models.ManyToManyField("Stable", related_name="ponies"))
|
||||||
])
|
])
|
||||||
new_apps = project_state.render()
|
Pony = project_state.apps.get_model("test_alflmm", "Pony")
|
||||||
Pony = new_apps.get_model("test_alflmm", "Pony")
|
|
||||||
|
|
||||||
project_state = self.apply_operations("test_alflmm", project_state, operations=[
|
project_state = self.apply_operations("test_alflmm", project_state, operations=[
|
||||||
migrations.AlterField("Pony", "places", models.ManyToManyField(to="Van", related_name="ponies"))
|
migrations.AlterField("Pony", "places", models.ManyToManyField(to="Van", related_name="ponies"))
|
||||||
])
|
])
|
||||||
|
|
||||||
# Ensure the new field actually works
|
# Ensure the new field actually works
|
||||||
new_apps = project_state.render()
|
Pony = project_state.apps.get_model("test_alflmm", "Pony")
|
||||||
Pony = new_apps.get_model("test_alflmm", "Pony")
|
|
||||||
p = Pony.objects.create(pink=False, weight=4.55)
|
p = Pony.objects.create(pink=False, weight=4.55)
|
||||||
p.places.create()
|
p.places.create()
|
||||||
self.assertEqual(p.places.count(), 1)
|
self.assertEqual(p.places.count(), 1)
|
||||||
|
@ -1238,7 +1225,7 @@ class OperationTests(OperationTestBase):
|
||||||
# Make sure there's no matching index
|
# Make sure there's no matching index
|
||||||
self.assertColumnNotExists("test_alorwrtto_rider", "_order")
|
self.assertColumnNotExists("test_alorwrtto_rider", "_order")
|
||||||
# Create some rows before alteration
|
# Create some rows before alteration
|
||||||
rendered_state = project_state.render()
|
rendered_state = project_state.apps
|
||||||
pony = rendered_state.get_model("test_alorwrtto", "Pony").objects.create(weight=50)
|
pony = rendered_state.get_model("test_alorwrtto", "Pony").objects.create(weight=50)
|
||||||
rendered_state.get_model("test_alorwrtto", "Rider").objects.create(pony=pony, friend_id=1)
|
rendered_state.get_model("test_alorwrtto", "Rider").objects.create(pony=pony, friend_id=1)
|
||||||
rendered_state.get_model("test_alorwrtto", "Rider").objects.create(pony=pony, friend_id=2)
|
rendered_state.get_model("test_alorwrtto", "Rider").objects.create(pony=pony, friend_id=2)
|
||||||
|
@ -1247,7 +1234,7 @@ class OperationTests(OperationTestBase):
|
||||||
operation.database_forwards("test_alorwrtto", editor, project_state, new_state)
|
operation.database_forwards("test_alorwrtto", editor, project_state, new_state)
|
||||||
self.assertColumnExists("test_alorwrtto_rider", "_order")
|
self.assertColumnExists("test_alorwrtto_rider", "_order")
|
||||||
# Check for correct value in rows
|
# Check for correct value in rows
|
||||||
updated_riders = new_state.render().get_model("test_alorwrtto", "Rider").objects.all()
|
updated_riders = new_state.apps.get_model("test_alorwrtto", "Rider").objects.all()
|
||||||
self.assertEqual(updated_riders[0]._order, 0)
|
self.assertEqual(updated_riders[0]._order, 0)
|
||||||
self.assertEqual(updated_riders[1]._order, 0)
|
self.assertEqual(updated_riders[1]._order, 0)
|
||||||
# And test reversal
|
# And test reversal
|
||||||
|
@ -1530,15 +1517,15 @@ class OperationTests(OperationTestBase):
|
||||||
operation.state_forwards("test_runpython", new_state)
|
operation.state_forwards("test_runpython", new_state)
|
||||||
self.assertEqual(new_state, project_state)
|
self.assertEqual(new_state, project_state)
|
||||||
# Test the database alteration
|
# Test the database alteration
|
||||||
self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 0)
|
self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 0)
|
||||||
with connection.schema_editor() as editor:
|
with connection.schema_editor() as editor:
|
||||||
operation.database_forwards("test_runpython", editor, project_state, new_state)
|
operation.database_forwards("test_runpython", editor, project_state, new_state)
|
||||||
self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 2)
|
self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 2)
|
||||||
# Now test reversal
|
# Now test reversal
|
||||||
self.assertTrue(operation.reversible)
|
self.assertTrue(operation.reversible)
|
||||||
with connection.schema_editor() as editor:
|
with connection.schema_editor() as editor:
|
||||||
operation.database_backwards("test_runpython", editor, project_state, new_state)
|
operation.database_backwards("test_runpython", editor, project_state, new_state)
|
||||||
self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 0)
|
self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 0)
|
||||||
# Now test we can't use a string
|
# Now test we can't use a string
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
migrations.RunPython("print 'ahahaha'")
|
migrations.RunPython("print 'ahahaha'")
|
||||||
|
@ -1555,7 +1542,7 @@ class OperationTests(OperationTestBase):
|
||||||
no_reverse_operation.database_forwards("test_runpython", editor, project_state, new_state)
|
no_reverse_operation.database_forwards("test_runpython", editor, project_state, new_state)
|
||||||
with self.assertRaises(NotImplementedError):
|
with self.assertRaises(NotImplementedError):
|
||||||
no_reverse_operation.database_backwards("test_runpython", editor, new_state, project_state)
|
no_reverse_operation.database_backwards("test_runpython", editor, new_state, project_state)
|
||||||
self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 2)
|
self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 2)
|
||||||
|
|
||||||
def create_ponies(models, schema_editor):
|
def create_ponies(models, schema_editor):
|
||||||
Pony = models.get_model("test_runpython", "Pony")
|
Pony = models.get_model("test_runpython", "Pony")
|
||||||
|
@ -1568,7 +1555,7 @@ class OperationTests(OperationTestBase):
|
||||||
operation = migrations.RunPython(create_ponies)
|
operation = migrations.RunPython(create_ponies)
|
||||||
with connection.schema_editor() as editor:
|
with connection.schema_editor() as editor:
|
||||||
operation.database_forwards("test_runpython", editor, project_state, new_state)
|
operation.database_forwards("test_runpython", editor, project_state, new_state)
|
||||||
self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 4)
|
self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 4)
|
||||||
# And deconstruction
|
# And deconstruction
|
||||||
definition = operation.deconstruct()
|
definition = operation.deconstruct()
|
||||||
self.assertEqual(definition[0], "RunPython")
|
self.assertEqual(definition[0], "RunPython")
|
||||||
|
@ -1586,8 +1573,8 @@ class OperationTests(OperationTestBase):
|
||||||
operation = migrations.RunPython(create_shetlandponies)
|
operation = migrations.RunPython(create_shetlandponies)
|
||||||
with connection.schema_editor() as editor:
|
with connection.schema_editor() as editor:
|
||||||
operation.database_forwards("test_runpython", editor, project_state, new_state)
|
operation.database_forwards("test_runpython", editor, project_state, new_state)
|
||||||
self.assertEqual(project_state.render().get_model("test_runpython", "Pony").objects.count(), 6)
|
self.assertEqual(project_state.apps.get_model("test_runpython", "Pony").objects.count(), 6)
|
||||||
self.assertEqual(project_state.render().get_model("test_runpython", "ShetlandPony").objects.count(), 2)
|
self.assertEqual(project_state.apps.get_model("test_runpython", "ShetlandPony").objects.count(), 2)
|
||||||
|
|
||||||
def test_run_python_atomic(self):
|
def test_run_python_atomic(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1606,26 +1593,26 @@ class OperationTests(OperationTestBase):
|
||||||
non_atomic_migration.operations = [migrations.RunPython(inner_method, atomic=False)]
|
non_atomic_migration.operations = [migrations.RunPython(inner_method, atomic=False)]
|
||||||
# If we're a fully-transactional database, both versions should rollback
|
# If we're a fully-transactional database, both versions should rollback
|
||||||
if connection.features.can_rollback_ddl:
|
if connection.features.can_rollback_ddl:
|
||||||
self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 0)
|
self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0)
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
with connection.schema_editor() as editor:
|
with connection.schema_editor() as editor:
|
||||||
atomic_migration.apply(project_state, editor)
|
atomic_migration.apply(project_state, editor)
|
||||||
self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 0)
|
self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0)
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
with connection.schema_editor() as editor:
|
with connection.schema_editor() as editor:
|
||||||
non_atomic_migration.apply(project_state, editor)
|
non_atomic_migration.apply(project_state, editor)
|
||||||
self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 0)
|
self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0)
|
||||||
# Otherwise, the non-atomic operation should leave a row there
|
# Otherwise, the non-atomic operation should leave a row there
|
||||||
else:
|
else:
|
||||||
self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 0)
|
self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0)
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
with connection.schema_editor() as editor:
|
with connection.schema_editor() as editor:
|
||||||
atomic_migration.apply(project_state, editor)
|
atomic_migration.apply(project_state, editor)
|
||||||
self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 0)
|
self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 0)
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
with connection.schema_editor() as editor:
|
with connection.schema_editor() as editor:
|
||||||
non_atomic_migration.apply(project_state, editor)
|
non_atomic_migration.apply(project_state, editor)
|
||||||
self.assertEqual(project_state.render().get_model("test_runpythonatomic", "Pony").objects.count(), 1)
|
self.assertEqual(project_state.apps.get_model("test_runpythonatomic", "Pony").objects.count(), 1)
|
||||||
# And deconstruction
|
# And deconstruction
|
||||||
definition = non_atomic_migration.operations[0].deconstruct()
|
definition = non_atomic_migration.operations[0].deconstruct()
|
||||||
self.assertEqual(definition[0], "RunPython")
|
self.assertEqual(definition[0], "RunPython")
|
||||||
|
|
|
@ -201,7 +201,7 @@ class StateTests(TestCase):
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
|
|
||||||
new_apps = project_state.render()
|
new_apps = project_state.apps
|
||||||
self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field_by_name("name")[0].max_length, 100)
|
self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field_by_name("name")[0].max_length, 100)
|
||||||
self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field_by_name("hidden")[0].null, False)
|
self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field_by_name("hidden")[0].null, False)
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ class StateTests(TestCase):
|
||||||
project_state.add_model_state(ModelState.from_model(D))
|
project_state.add_model_state(ModelState.from_model(D))
|
||||||
project_state.add_model_state(ModelState.from_model(E))
|
project_state.add_model_state(ModelState.from_model(E))
|
||||||
project_state.add_model_state(ModelState.from_model(F))
|
project_state.add_model_state(ModelState.from_model(F))
|
||||||
final_apps = project_state.render()
|
final_apps = project_state.apps
|
||||||
self.assertEqual(len(final_apps.get_models()), 6)
|
self.assertEqual(len(final_apps.get_models()), 6)
|
||||||
|
|
||||||
# Now make an invalid ProjectState and make sure it fails
|
# Now make an invalid ProjectState and make sure it fails
|
||||||
|
@ -340,7 +340,7 @@ class StateTests(TestCase):
|
||||||
project_state.add_model_state(ModelState.from_model(C))
|
project_state.add_model_state(ModelState.from_model(C))
|
||||||
project_state.add_model_state(ModelState.from_model(F))
|
project_state.add_model_state(ModelState.from_model(F))
|
||||||
with self.assertRaises(InvalidBasesError):
|
with self.assertRaises(InvalidBasesError):
|
||||||
project_state.render()
|
project_state.apps
|
||||||
|
|
||||||
def test_render_unique_app_labels(self):
|
def test_render_unique_app_labels(self):
|
||||||
"""
|
"""
|
||||||
|
@ -360,8 +360,7 @@ class StateTests(TestCase):
|
||||||
project_state = ProjectState()
|
project_state = ProjectState()
|
||||||
project_state.add_model_state(ModelState.from_model(A))
|
project_state.add_model_state(ModelState.from_model(A))
|
||||||
project_state.add_model_state(ModelState.from_model(B))
|
project_state.add_model_state(ModelState.from_model(B))
|
||||||
final_apps = project_state.render()
|
self.assertEqual(len(project_state.apps.get_models()), 2)
|
||||||
self.assertEqual(len(final_apps.get_models()), 2)
|
|
||||||
|
|
||||||
def test_equality(self):
|
def test_equality(self):
|
||||||
"""
|
"""
|
||||||
|
@ -432,20 +431,19 @@ class StateTests(TestCase):
|
||||||
project_state.add_model_state(ModelState.from_model(Author))
|
project_state.add_model_state(ModelState.from_model(Author))
|
||||||
project_state.add_model_state(ModelState.from_model(Book))
|
project_state.add_model_state(ModelState.from_model(Book))
|
||||||
project_state.add_model_state(ModelState.from_model(Magazine))
|
project_state.add_model_state(ModelState.from_model(Magazine))
|
||||||
rendered_state = project_state.render()
|
self.assertEqual(len(project_state.apps.get_models()), 3)
|
||||||
self.assertEqual(len(rendered_state.get_models()), 3)
|
|
||||||
|
|
||||||
# now make an invalid one with a ForeignKey
|
# now make an invalid one with a ForeignKey
|
||||||
project_state = ProjectState()
|
project_state = ProjectState()
|
||||||
project_state.add_model_state(ModelState.from_model(Book))
|
project_state.add_model_state(ModelState.from_model(Book))
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
rendered_state = project_state.render()
|
project_state.apps
|
||||||
|
|
||||||
# and another with ManyToManyField
|
# and another with ManyToManyField
|
||||||
project_state = ProjectState()
|
project_state = ProjectState()
|
||||||
project_state.add_model_state(ModelState.from_model(Magazine))
|
project_state.add_model_state(ModelState.from_model(Magazine))
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
rendered_state = project_state.render()
|
project_state.apps
|
||||||
|
|
||||||
def test_real_apps(self):
|
def test_real_apps(self):
|
||||||
"""
|
"""
|
||||||
|
@ -465,12 +463,12 @@ class StateTests(TestCase):
|
||||||
project_state = ProjectState()
|
project_state = ProjectState()
|
||||||
project_state.add_model_state(ModelState.from_model(TestModel))
|
project_state.add_model_state(ModelState.from_model(TestModel))
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
project_state.render()
|
project_state.apps
|
||||||
|
|
||||||
# If we include the real app it should succeed
|
# If we include the real app it should succeed
|
||||||
project_state = ProjectState(real_apps=["contenttypes"])
|
project_state = ProjectState(real_apps=["contenttypes"])
|
||||||
project_state.add_model_state(ModelState.from_model(TestModel))
|
project_state.add_model_state(ModelState.from_model(TestModel))
|
||||||
rendered_state = project_state.render()
|
rendered_state = project_state.apps
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
len([x for x in rendered_state.get_models() if x._meta.app_label == "migrations"]),
|
len([x for x in rendered_state.get_models() if x._meta.app_label == "migrations"]),
|
||||||
1,
|
1,
|
||||||
|
@ -538,4 +536,4 @@ class ModelStateTests(TestCase):
|
||||||
project_state = ProjectState()
|
project_state = ProjectState()
|
||||||
project_state.add_model_state(state)
|
project_state.add_model_state(state)
|
||||||
with self.assertRaisesMessage(InvalidBasesError, "Cannot resolve bases for [<ModelState: 'app.Model'>]"):
|
with self.assertRaisesMessage(InvalidBasesError, "Cannot resolve bases for [<ModelState: 'app.Model'>]"):
|
||||||
project_state.render()
|
project_state.apps
|
||||||
|
|
Loading…
Reference in New Issue