Jest to testowane z grubsza, więc nie zapomnij wykonać kopii zapasowej bazy danych !!!
Na przykład istnieją dwie aplikacje: src_app
i dst_app
, chcemy przenieść model MoveMe
z src_app
do dst_app
.
Utwórz puste migracje dla obu aplikacji:
python manage.py makemigrations --empty src_app
python manage.py makemigrations --empty dst_app
Załóżmy, że nowe migracje to, XXX1_src_app_new
a XXX1_dst_app_new
poprzednie najpopularniejsze migracje to XXX0_src_app_old
i XXX0_dst_app_old
.
Dodaj operację, która zmienia nazwę tabeli dla MoveMe
modelu i zmienia nazwę jej app_label w ProjectState na XXX1_dst_app_new
. Nie zapomnij dodać zależności od XXX0_src_app_old
migracji. Wynikowa XXX1_dst_app_new
migracja to:
from __future__ import unicode_literals
from django.db import models, migrations
class MoveModelFromOtherApp(migrations.operations.base.Operation):
def __init__(self, name, old_app_label):
self.name = name
self.old_app_label = old_app_label
def state_forwards(self, app_label, state):
apps = state.render(skip_cache=True)
model = apps.get_model(self.old_app_label, self.name)
related_objects = model._meta.get_all_related_objects()
related_m2m_objects = model._meta.get_all_related_many_to_many_objects()
state.models[app_label, self.name.lower()] = state.models.pop(
(self.old_app_label, self.name.lower())
)
state.models[app_label, self.name.lower()].app_label = app_label
for model_state in state.models.values():
try:
i = model_state.bases.index("%s.%s" % (self.old_app_label, self.name.lower()))
model_state.bases = model_state.bases[:i] + ("%s.%s" % (app_label, self.name.lower()),) + model_state.bases[i+1:]
except ValueError:
pass
for related_object in (related_objects + related_m2m_objects):
if related_object.model == model:
related_key = (app_label, self.name.lower())
else:
related_key = (
related_object.model._meta.app_label,
related_object.model._meta.object_name.lower(),
)
new_fields = []
for name, field in state.models[related_key].fields:
if name == related_object.field.name:
field = field.clone()
field.rel.to = "%s.%s" % (app_label, self.name)
new_fields.append((name, field))
state.models[related_key].fields = new_fields
def database_forwards(self, app_label, schema_editor, from_state, to_state):
old_apps = from_state.render()
new_apps = to_state.render()
old_model = old_apps.get_model(self.old_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):
schema_editor.alter_db_table(
new_model,
old_model._meta.db_table,
new_model._meta.db_table,
)
related_objects = old_model._meta.get_all_related_objects()
related_m2m_objects = old_model._meta.get_all_related_many_to_many_objects()
for related_object in (related_objects + related_m2m_objects):
if related_object.model == old_model:
model = new_model
related_key = (app_label, self.name.lower())
else:
model = related_object.model
related_key = (
related_object.model._meta.app_label,
related_object.model._meta.object_name.lower(),
)
to_field = new_apps.get_model(
*related_key
)._meta.get_field_by_name(related_object.field.name)[0]
schema_editor.alter_field(
model,
related_object.field,
to_field,
)
def database_backwards(self, app_label, schema_editor, from_state, to_state):
self.old_app_label, app_label = app_label, self.old_app_label
self.database_forwards(app_label, schema_editor, from_state, to_state)
app_label, self.old_app_label = self.old_app_label, app_label
def describe(self):
return "Move %s from %s" % (self.name, self.old_app_label)
class Migration(migrations.Migration):
dependencies = [
('dst_app', 'XXX0_dst_app_old'),
('src_app', 'XXX0_src_app_old'),
]
operations = [
MoveModelFromOtherApp('MoveMe', 'src_app'),
]
Dodaj zależność od XXX1_dst_app_new
do XXX1_src_app_new
. XXX1_src_app_new
to migracja bez operacji, która jest potrzebna, aby upewnić się, że przyszłe src_app
migracje zostaną wykonane później XXX1_dst_app_new
.
Przejdź MoveMe
z src_app/models.py
do dst_app/models.py
. Następnie uruchomić:
python manage.py migrate
To wszystko!