Cómo mover un modelo entre dos aplicaciones de Django (Django 1.7)

133

Así que hace aproximadamente un año comencé un proyecto y, como todos los nuevos desarrolladores, realmente no me enfoqué demasiado en la estructura, sin embargo, ahora que estoy más junto con Django, comenzó a parecer que el diseño de mi proyecto, principalmente mis modelos, tienen una estructura horrible. .

Tengo modelos mantenidos principalmente en una sola aplicación y realmente la mayoría de estos modelos deberían estar en sus propias aplicaciones individuales, intenté resolver esto y moverlos hacia el sur, sin embargo, lo encontré complicado y realmente difícil debido a las claves externas, etc.

Sin embargo, debido a Django 1.7 y al soporte integrado para las migraciones, ¿hay una mejor manera de hacerlo ahora?

Sam Buckingham
fuente
44
Es posible que desee considerar cambiar la respuesta aceptada.
Babken Vardanyan
Para las personas que se encuentren con esto en el futuro: Django 3.x aquí, y el enfoque detallado en realpython.com/move-django-model/… funcionó para mí. Tenía varias claves foráneas entre los modelos dentro de la aplicación anterior y los modelos de la nueva aplicación.
pradeepcep

Respuestas:

16

Estoy eliminando la respuesta anterior, ya que puede provocar la pérdida de datos. Como mencionó Ozan , podemos crear 2 migraciones, una en cada aplicación. Los comentarios debajo de esta publicación se refieren a mi antigua respuesta.

Primera migración para eliminar el modelo de la primera aplicación.

$ python manage.py makemigrations old_app --empty

Edite el archivo de migración para incluir estas operaciones.

class Migration(migrations.Migration):

    database_operations = [migrations.AlterModelTable('TheModel', 'newapp_themodel')]

    state_operations = [migrations.DeleteModel('TheModel')]

    operations = [
      migrations.SeparateDatabaseAndState(
        database_operations=database_operations,
        state_operations=state_operations)
    ]

Segunda migración que depende de la primera migración y crea la nueva tabla en la segunda aplicación. Después de mover el código del modelo a la segunda aplicación

$ python manage.py makemigrations new_app 

y edite el archivo de migración a algo como esto.

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]
ChillarAnand
fuente
Tengo datos existentes y muchos de los cuales simplemente no puedo perder, ¿es posible hacerlo con esto?
Sam Buckingham
@KevinChristopherHenry Modificó el código. Esto conserva los datos existentes.
ChillarAnand
@SamBuckingham Sí, puede intentar con el código modificado para migrar sin perder los datos.
ChillarAnand
2
Creo que realmente será la mejor manera, gracias por toda la ayuda, muchachos, ha sido brillante.
Sam Buckingham
1
En mi opinión, esta es una solución incorrecta, el supuesto básico de las migraciones es que si ejecuta ./manage.py migratetodo terminará en buen estado. Fingir manualmente las migraciones es una OMI de una manera incorrecta.
jb.
341

Esto se puede hacer con bastante facilidad usando migrations.SeparateDatabaseAndState. Básicamente, utilizamos una operación de base de datos para cambiar el nombre de la tabla simultáneamente con dos operaciones de estado para eliminar el modelo del historial de una aplicación y crearlo en el de otra.

Eliminar de la aplicación anterior

python manage.py makemigrations old_app --empty

En la migración:

class Migration(migrations.Migration):

    dependencies = []

    database_operations = [
        migrations.AlterModelTable('TheModel', 'newapp_themodel')
    ]

    state_operations = [
        migrations.DeleteModel('TheModel')
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=database_operations,
            state_operations=state_operations)
    ]

Agregar a nueva aplicación

Primero, copie el modelo a la nueva aplicación model.py, luego:

python manage.py makemigrations new_app

Esto generará una migración con una CreateModeloperación ingenua como única operación. Envuelva eso en una SeparateDatabaseAndStateoperación tal que no intentemos recrear la tabla. Incluya también la migración previa como una dependencia:

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]
ozan
fuente
14
Muy buena explicación. Esta debería ser la respuesta, al cambiar el nombre de la tabla, evitará perder datos.
Remiz
11
Esta es la mejor manera de hacerlo y es mucho mejor que la mía. Se agregó una nota en la parte superior de mi respuesta.
Chillar y
44
Hice esto, pero cuando ejecuto "makemigrations" en la nueva aplicación después de esto, genera una migración de AlterModelTable que lo renombra a Ninguno.
Diego Ponciano
44
Encontré una manera de resolver mi problema en base a estas instrucciones. El problema es más complicado si tiene referencias de clave externa que son campos obligatorios. Tuve que agregar un par de pasos para mover las referencias.
Nostalg.io
14
Debido a múltiples solicitudes, he creado una respuesta detallada sobre las migraciones de modelos FK con un ejemplo de GitHub. stackoverflow.com/questions/30601107/…
Nostalg.io
26

Encontré el mismo problema. La respuesta de Ozan me ayudó mucho, pero desafortunadamente no fue suficiente. De hecho, tenía varios ForeignKey vinculados al modelo que quería mover. Después de un dolor de cabeza, encontré la solución, así que decidí publicarla para resolver el tiempo de las personas.

Necesita 2 pasos más:

  1. Antes de hacer nada, cambiar toda su ForeignKeyvinculación a TheModeldentro Integerfield. Entonces correpython manage.py makemigrations
  2. Después de seguir los pasos de Ozan, reconvierta sus claves foráneas: vuelva a colocarlas en ForeignKey(TheModel)lugar de IntegerField(). Luego realice las migraciones nuevamente ( python manage.py makemigrations). Luego puede migrar y debería funcionar ( python manage.py migrate)

Espero eso ayude. Por supuesto, pruébelo en local antes de intentarlo en producción para evitar malas sorpresas :)

otranzer
fuente
8
¿Qué pasa con las relaciones ManyToManyField?
Tomcounsell
1
@tomcounsell gran comentario, supongo que al agregar un modelo específico a través de migraciones. Se requiere una gran cantidad de trabajo para dejar los datos intactos ...
Wtower
Dado que una relación de muchos a muchos suele ser solo una tabla con dos claves foráneas, desde el punto de vista de SQL, puede aplicar el truco de esta respuesta. Pero para lograr esto solo a través de Django, un enfoque que puedo pensar sería en la línea de respuesta @ozan, excepto que el primer paso sería duplicar las tablas involucradas en la relación MTM (una versión de los engaños en cada aplicación) , migre todas las claves externas a la nueva aplicación y solo luego elimine los engaños en la aplicación anterior. Descargo de responsabilidad: no he probado :)
Arnaud P
15

Cómo lo hice (probado en Django == 1.8, con postgres, así que probablemente también 1.7)

Situación

app1.YourModel

pero quieres que vaya a: app2.YourModel

  1. Copie YourModel (el código) de app1 a app2.
  2. agregue esto a app2.YourModel:

    Class Meta:
        db_table = 'app1_yourmodel'
  3. $ python manage.py makemigrations app2

  4. Se realiza una nueva migración (por ejemplo, 0009_auto_something.py) en app2 con una declaración migrations.CreateModel (), mueva esta declaración a la migración inicial de app2 (por ejemplo, 0001_initial.py) (será como siempre ha estado allí). Y ahora elimine la migración creada = 0009_auto_something.py

  5. Así como actúas, como app2.YourModel siempre ha estado allí, ahora elimina la existencia de app1.YourModel de tus migraciones. Significado: comente las declaraciones CreateModel y cada ajuste o migración de datos que utilizó después de eso.

  6. Y, por supuesto, cada referencia a app1.YourModel debe cambiarse a app2.YourModel a través de su proyecto. Además, no olvide que todas las claves foráneas posibles para app1.YourModel en las migraciones deben cambiarse a app2.YourModel

  7. Ahora, si hace $ python manage.py migrate, nada ha cambiado, también cuando hace $ python manage.py makemigrations, no se ha detectado nada nuevo.

  8. Ahora el toque final: elimine Class Meta de app2.YourModel y haga $ python manage.py makemigrations app2 && python manage.py migrate app2 (si observa esta migración verá algo como esto :)

        migrations.AlterModelTable(
        name='yourmodel',
        table=None,
    ),

table = None, significa que tomará el nombre de tabla predeterminado, que en este caso será app2_yourmodel.

  1. HECHO, con los datos guardados.

PS durante la migración verá que esa content_type app1.yourmodel se ha eliminado y se puede eliminar. Puedes decir sí a eso, pero solo si no lo usas. En caso de que dependa en gran medida de que tenga FK para ese tipo de contenido intacto, no responda sí o no todavía, pero vaya al db esa vez manualmente, elimine el tipo de contenido app2.yourmodel y cambie el nombre de la aplicación contenttype1. yourmodel a app2.yourmodel, y luego continúe respondiendo no.

Michael van de Waeter
fuente
3
Si bien esta solución es definitivamente "más pirata" que la de @ ozan y definitivamente necesita más edición, funcionó muy bien para mí (y está bien editar las migraciones; según los documentos, se supone que son editables).
pgcd
1
Posiblemente también use la app_label = 'app1'opción meta.
Wtower
¡Genio! Esto funcionó muy bien para mí para las relaciones ForeignKey. Supongo que esto también funcionará para los campos ManyToMany.
Babken Vardanyan
Seguí tus pasos, pero el campo en algunos modelos pertenecientes a app1 consiste en una clave externa con una relación recursiva con el modelo (myModel) que se moverá. Al igual que field1 = models.ForeignKey('app1.myModel').cuando migro, recibo un ValueError que dice esofield1 was declared with a lazy reference to 'app1.myModel' but app 'app1' doesn't provide model 'MyModel'
Deesha
12

Me ponen nervioso las migraciones de codificación manual (como lo requiere la respuesta de Ozan ), por lo que lo siguiente combina las estrategias de Ozan y Michael para minimizar la cantidad de codificación manual requerida:

  1. Antes de mover cualquier modelo, asegúrese de estar trabajando con una línea base limpia ejecutando makemigrations.
  2. Mueva el código para el Modelo de app1aapp2
  3. Según lo recomendado por @Michael, apuntamos el nuevo modelo a la tabla de base de datos anterior usando la db_tableopción Meta en el modelo "nuevo":

    class Meta:
        db_table = 'app1_yourmodel'
  4. Ejecutar makemigrations. Esto generará CreateModelin app2y DeleteModelin app1. Técnicamente, estas migraciones se refieren exactamente a la misma tabla y eliminarían (incluidos todos los datos) y volverían a crear la tabla.

  5. En realidad, no queremos (o necesitamos) hacer nada a la mesa. Solo necesitamos que Django crea que el cambio se ha realizado. Según la respuesta de @ Ozan, la state_operationsbandera SeparateDatabaseAndStatehace esto. Así que envolvemos todas las migrationsentradas EN AMBOS ARCHIVOS DE MIGRACIONES con SeparateDatabaseAndState(state_operations=[...]). Por ejemplo,

    operations = [
        ...
        migrations.DeleteModel(
            name='YourModel',
        ),
        ...
    ]

    se convierte

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=[
            ...
            migrations.DeleteModel(
                name='YourModel',
            ),
            ...
        ])
    ]
  6. También debe asegurarse de que la nueva CreateModelmigración "virtual" dependa de cualquier migración que realmente haya creado o alterado la tabla original . Por ejemplo, si sus nuevas migraciones son app2.migrations.0004_auto_<date>(para el Create) y app1.migrations.0007_auto_<date>(para el Delete), lo más simple es:

    • Abra app1.migrations.0007_auto_<date>y copie su app1dependencia (por ejemplo ('app1', '0006...'),). Esta es la migración "inmediatamente anterior" app1y debe incluir dependencias de toda la lógica de construcción del modelo real.
    • Abra app2.migrations.0004_auto_<date>y agregue la dependencia que acaba de copiar a su dependencieslista.

Si tiene ForeignKeyrelación (s) con el modelo que está moviendo, lo anterior puede no funcionar. Esto sucede porque:

  • Las dependencias no se crean automáticamente para los ForeignKeycambios.
  • No queremos ajustar los ForeignKeycambios, por state_operationslo que debemos asegurarnos de que estén separados de las operaciones de la tabla.

NOTA: Django 2.2 agregó una advertencia ( models.E028) que rompe este método. Es posible que pueda solucionarlo, managed=Falsepero no lo he probado.

El conjunto "mínimo" de operaciones difiere según la situación, pero el siguiente procedimiento debería funcionar para la mayoría / todas las ForeignKeymigraciones:

  1. COPIE el modelo de app1a app2, establezcadb_table , pero NO cambie ninguna referencia de FK.
  2. Ejecute makemigrationsy ajuste toda la app2migración enstate_operations (ver arriba)
    • Como se indicó anteriormente, agregue una dependencia en app2 CreateTablela última app1migración
  3. Señale todas las referencias de FK al nuevo modelo. Si no está utilizando referencias de cadena, mueva el modelo anterior al final demodels.py (NO lo elimine) para que no compita con la clase importada.
  4. Ejecuta makemigrationspero NO envuelvas nada state_operations(los cambios de FK deberían suceder). Agregue una dependencia en todas las ForeignKeymigraciones (es decir AlterField) a la CreateTablemigración en app2(necesitará esta lista para el siguiente paso, así que haga un seguimiento de ellas). Por ejemplo:

    • Encuentre la migración que incluye CreateModeleg app2.migrations.0002_auto_<date>y copie el nombre de esa migración.
    • Encuentre todas las migraciones que tengan una ForeignKey para ese modelo (por ejemplo, buscando app2.YourModelmigraciones como:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
          ]
      
          operations = [
              migrations.AlterField(
                  model_name='relatedmodel',
                  name='fieldname',
                  field=models.ForeignKey(... to='app2.YourModel'),
              ),
          ]
    • Agregue la CreateModelmigración como una dependencia:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
              ('app2', '0002_auto_<date>'),
          ]  
  5. Eliminar los modelos de app1

  6. Ejecute makemigrationsy ajuste la app1migración enstate_operations .
    • Agregue una dependencia a todas las ForeignKeymigraciones (es decir AlterField) del paso anterior (puede incluir migraciones en app1y app2).
    • Cuando construí estas migraciones, DeleteTableya dependía de las AlterFieldmigraciones, por lo que no necesitaba aplicarlas manualmente (es decir, Alterantes Delete).

En este punto, Django está listo. El nuevo modelo apunta a la tabla anterior y las migraciones de Django lo han convencido de que todo se ha reubicado adecuadamente. La gran advertencia (de la respuesta de @ Michael) es que ContentTypese crea una nueva para el nuevo modelo. Si vincula (p. Ej., Por ForeignKey) a tipos de contenido, deberá crear una migración para actualizar la ContentTypetabla.

Quería limpiar después de mí (opciones de Meta y nombres de tablas), así que utilicé el siguiente procedimiento (de @ Michael):

  1. Eliminar la db_tableentrada Meta
  2. Ejecutar makemigrationsnuevamente para generar el cambio de nombre de la base de datos
  3. Edite esta última migración y asegúrese de que depende de la DeleteTablemigración. No parece que deba ser necesario, ya que Deletedebe ser puramente lógico, pero me he encontrado con errores (por ejemplo app1_yourmodel, no existe) si no lo hago.
Claytond
fuente
Esto funcionó perfectamente, gracias! No creo que la edición de la última migración sea importante ya que de todos modos está en la parte inferior del árbol de dependencias.
James Meakin
1
¡Buena respuesta! Creo que necesita agregar un paréntesis de cierre a las migraciones. SeparateDatabaseAndState, ¿verdad?
cajero automático
Esto funcionó para mí. Tampoco edité la última migración (paso 3, la última línea de la respuesta completa) como @JamesMeakin y todavía funcionó bien
Megawatt
en el segundo escenario, el de FK, el segundo paso falló para mí con un error que tiene sentido:table_name: (models.E028) db_table 'table_name' is used by multiple models: app1.Model, app2.Model.
Mihai Zamfir
He usado el procedimiento un par de veces. Si compara la documentación de 2.2 ( docs.djangoproject.com/en/2.2/ref/checks ) y 2.1 ( docs.djangoproject.com/en/2.1/ref/checks ), puede ver que se agregó en 2.2. Es posible evitarlo, managed=Falsepero no estoy en ningún lugar para verificarlo.
Claytond
1

Otra alternativa hacky si los datos no son grandes o demasiado complicados, pero aún son importantes para mantener, es:

  • Obtenga accesorios de datos utilizando manage.py dumpdata
  • Continuar con los cambios y migraciones del modelo correctamente, sin relacionar los cambios.
  • Global reemplaza los accesorios del modelo antiguo y los nombres de las aplicaciones a los nuevos
  • Cargue datos usando manage.py loaddata
Wtower
fuente
1

Copiado de mi respuesta en https://stackoverflow.com/a/47392970/8971048

En caso de que necesite mover el modelo y ya no tenga acceso a la aplicación (o no desee el acceso), puede crear una nueva Operación y considerar crear un nuevo modelo solo si el modelo migrado no existe.

En este ejemplo, paso 'MyModel' de old_app a myapp.

class MigrateOrCreateTable(migrations.CreateModel):
    def __init__(self, source_table, dst_table, *args, **kwargs):
        super(MigrateOrCreateTable, self).__init__(*args, **kwargs)
        self.source_table = source_table
        self.dst_table = dst_table

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        table_exists = self.source_table in schema_editor.connection.introspection.table_names()
        if table_exists:
            with schema_editor.connection.cursor() as cursor:
                cursor.execute("RENAME TABLE {} TO {};".format(self.source_table, self.dst_table))
        else:
            return super(MigrateOrCreateTable, self).database_forwards(app_label, schema_editor, from_state, to_state)


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_some_migration'),
    ]

    operations = [
        MigrateOrCreateTable(
            source_table='old_app_mymodel',
            dst_table='myapp_mymodel',
            name='MyModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=18))
            ],
        ),
    ]
Cantante Gal
fuente
No agregue la misma respuesta a varias preguntas. Responda la mejor y marque el resto como duplicados. Consulte ¿Es aceptable agregar una respuesta duplicada a varias preguntas?
Petter Friberg
0

Esto se prueba aproximadamente, ¡así que no olvide hacer una copia de seguridad de su base de datos!

Por ejemplo, hay dos aplicaciones: src_appy dst_app, queremos mover el modelo MoveMede src_appa dst_app.

Cree migraciones vacías para ambas aplicaciones:

python manage.py makemigrations --empty src_app
python manage.py makemigrations --empty dst_app

Supongamos que las nuevas migraciones son XXX1_src_app_newy XXX1_dst_app_new, previamente, las principales migraciones son XXX0_src_app_oldy XXX0_dst_app_old.

Agregue una operación que MoveMecambie el nombre de la tabla para el modelo y cambie el nombre de su app_label en ProjectState a XXX1_dst_app_new. No olvides agregar dependencia a la XXX0_src_app_oldmigración. La XXX1_dst_app_newmigración resultante es:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

# this operations is almost the same as RenameModel
# https://github.com/django/django/blob/1.7/django/db/migrations/operations/models.py#L104
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):

        # Get all of the related objects we need to repoint
        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()
        # Rename the model
        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
        # Repoint the FKs and M2Ms pointing to us
        for related_object in (related_objects + related_m2m_objects):
            # Use the new related key for self referential related 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):
            # Move the main table
            schema_editor.alter_db_table(
                new_model,
                old_model._meta.db_table,
                new_model._meta.db_table,
            )
            # Alter the fields pointing to us
            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'),
    ]

Agregar dependencia XXX1_dst_app_newa XXX1_src_app_new. XXX1_src_app_newes una migración sin operación que se necesita para garantizar que las futuras src_appmigraciones se ejecuten después XXX1_dst_app_new.

Pasar MoveMede src_app/models.pya dst_app/models.py. Entonces corre:

python manage.py migrate

¡Eso es todo!

Sergey Fedoseev
fuente
Tenga en cuenta que este código probablemente solo sea útil para django 1.7. Probar esto en django 2.0 no funcionará. Esto también significa que el uso de este mecanismo para mover modelos agrega gastos generales de mantenimiento a la actualización de su versión de django.
Paul en 't Hout
0

Puedes probar lo siguiente (no probado):

  1. mover el modelo de src_appadest_app
  2. migrar dest_app; asegúrese de que la migración del esquema dependa de la última src_appmigración ( https://docs.djangoproject.com/en/dev/topics/migrations/#migration-files )
  3. agregar una migración de datos a dest_app, que copia todos los datos desrc_app
  4. migrar src_app; asegúrese de que la migración del esquema depende de la última migración (de datos) de dest_app, es decir, la migración del paso 3

Tenga en cuenta que copiará toda la tabla, en lugar de moverla , pero de esa manera ambas aplicaciones no tienen que tocar una tabla que pertenece a la otra aplicación, lo que creo que es más importante.

Entusiasta de la web
fuente
0

Digamos que está moviendo el modelo TheModel de app_a a app_b.

Una solución alternativa es alterar las migraciones existentes a mano. La idea es que cada vez que vea una operación que altere TheModel en las migraciones de app_a, copie esa operación al final de la migración inicial de app_b. Y cada vez que vea una referencia 'app_a.TheModel' en las migraciones de app_a, la cambia a 'app_b.TheModel'.

Acabo de hacer esto para un proyecto existente, donde quería extraer cierto modelo a una aplicación reutilizable. El procedimiento fue sin problemas. Supongo que las cosas serían mucho más difíciles si hubiera referencias de app_b a app_a. Además, tenía una Meta.db_table definida manualmente para mi modelo que podría haber ayudado.

En particular, terminarás con un historial de migración alterado. Esto no importa, incluso si tiene una base de datos con las migraciones originales aplicadas. Si tanto las migraciones originales como las reescritas terminan con el mismo esquema de base de datos, dicha reescritura debería estar bien.

akaariai
fuente
0
  1. cambiar los nombres de modelos antiguos a 'model_name_old'
  2. hacer migraciones
  3. crear nuevos modelos llamados 'model_name_new' con relaciones idénticas en los modelos relacionados (por ejemplo, el modelo de usuario ahora tiene user.blog_old y user.blog_new)
  4. hacer migraciones
  5. escribir una migración personalizada que migre todos los datos a las nuevas tablas del modelo
  6. pruebe al máximo estas migraciones comparando las copias de seguridad con nuevas copias de db antes y después de ejecutar las migraciones
  7. cuando todo sea satisfactorio, elimine los modelos antiguos
  8. hacer migraciones
  9. cambie los nuevos modelos al nombre correcto 'model_name_new' -> 'model_name'
  10. probar toda la gran cantidad de migraciones en un servidor provisional
  11. desconecte su sitio de producción durante unos minutos para ejecutar todas las migraciones sin que los usuarios interfieran

Haga esto individualmente para cada modelo que necesite ser movido. No sugeriría hacer lo que dice la otra respuesta al cambiar a números enteros y volver a claves externas Existe la posibilidad de que las nuevas claves externas sean diferentes y las filas puedan tener diferentes ID después de las migraciones y no quería correr ningún riesgo de identificadores no coincidentes al volver a las claves externas.

Tomcounsell
fuente