Come spostare un modello tra due app Django (Django 1.7)


133

Quindi circa un anno fa ho iniziato un progetto e come tutti i nuovi sviluppatori non mi sono concentrato molto sulla struttura, tuttavia ora sono più avanti insieme a Django che ha iniziato a sembrare che il layout del mio progetto principalmente i miei modelli siano orribili nella struttura .

Ho modelli principalmente presenti in una singola app e in realtà la maggior parte di questi modelli dovrebbero essere nelle loro singole app, ho provato a risolverlo e spostarli a sud, ma l'ho trovato difficile e davvero difficile a causa dell'ect delle chiavi esterne.

Tuttavia, a causa di Django 1.7 e del supporto integrato per le migrazioni, esiste un modo migliore per farlo ora?


4
Potresti voler considerare di cambiare la risposta accettata.
Babken Vardanyan,

Per le persone che si imbattono in questo in futuro: Django 3.x qui, e l'approccio dettagliato su realpython.com/move-django-model/… ha funzionato per me. Avevo più chiavi esterne tra i modelli all'interno della vecchia app e i modelli nella nuova app.
pradeepcep,

Risposte:


16

Sto rimuovendo la vecchia risposta che potrebbe provocare la perdita di dati. Come menzionato ozan , possiamo creare 2 migrazioni una per ogni app. I commenti sotto questo post si riferiscono alla mia vecchia risposta.

Prima migrazione per rimuovere il modello dalla prima app.

$ python manage.py makemigrations old_app --empty

Modifica il file di migrazione per includere queste operazioni.

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)
    ]

Seconda migrazione che dipende dalla prima migrazione e crea la nuova tabella nella seconda app. Dopo aver spostato il codice modello nella seconda app

$ python manage.py makemigrations new_app 

e modifica il file di migrazione in qualcosa del genere.

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)
    ]

Ho dei dati esistenti e molti di quelli che semplicemente non posso perdere, è forse possibile farlo con questo?
Sam Buckingham,

@KevinChristopherHenry Modificato il codice. Ciò preserva i dati esistenti.
ChillarAnand

@SamBuckingham Sì, puoi provare con il codice modificato per migrare senza perdere i dati.
ChillarAnand

2
Penso che sarà davvero il modo migliore, grazie per tutto l'aiuto ragazzi è stato geniale.
Sam Buckingham,

1
IMO questa è una soluzione sbagliata, l'ipotesi di base delle migrazioni è che se si esegue ./manage.py migratetutto finirà in buono stato. La falsificazione manuale delle migrazioni è un modo sbagliato dell'IMO.
jb.

341

Questo può essere fatto abbastanza facilmente usando migrations.SeparateDatabaseAndState. Fondamentalmente, utilizziamo un'operazione di database per rinominare la tabella contemporaneamente con due operazioni di stato per rimuovere il modello dalla cronologia di un'app e crearlo in un'altra.

Rimuovi dalla vecchia app

python manage.py makemigrations old_app --empty

Nella migrazione:

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)
    ]

Aggiungi a nuova app

Innanzitutto, copia il modello sul modello.py della nuova app, quindi:

python manage.py makemigrations new_app

Ciò genererà una migrazione con un'operazione ingenua CreateModelcome unica operazione. Avvolgilo in SeparateDatabaseAndStateun'operazione in modo tale che non proviamo a ricreare la tabella. Includi anche la migrazione precedente come dipendenza:

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)
    ]

14
Davvero una buona spiegazione. Questa dovrebbe essere la risposta, rinominando la tabella eviti di perdere dati.
Remiz,

11
Questo è il modo migliore per farlo ed è molto meglio del mio. Aggiunta nota in cima alla mia risposta.
Chillar e il

4
L'ho fatto, ma quando eseguo "makemigrations" sul newapp dopo questo, genera una migrazione AlterModelTable rinominandolo in Nessuno.
Diego Ponciano,

4
Ho trovato un modo per risolvere il mio problema sulla base di queste istruzioni. Il problema è più complicato se si hanno riferimenti a chiave esterna che sono campi obbligatori. Ho dovuto aggiungere un paio di passaggi per spostare i riferimenti.
Nostalg.io

14
A causa di molteplici richieste, ho creato una risposta dettagliata sulle migrazioni del modello FK con un esempio di GitHub. stackoverflow.com/questions/30601107/...
Nostalg.io

26

Ho riscontrato lo stesso problema. La risposta di Ozan mi ha aiutato molto, ma sfortunatamente non è stato sufficiente. In effetti avevo diversi ForeignKey collegati al modello che volevo spostare. Dopo qualche mal di testa ho trovato la soluzione, quindi ho deciso di pubblicarla per risolvere il tempo delle persone.

Hai bisogno di altri 2 passaggi:

  1. Prima di fare qualsiasi cosa, cambia tutti i tuoi ForeignKeycollegamenti TheModelin Integerfield. Quindi corripython manage.py makemigrations
  2. Dopo aver eseguito i passaggi di Ozan, riconvertisci le tue chiavi esterne: rimetti ForeignKey(TheModel)invece di IntegerField(). Quindi eseguire nuovamente le migrazioni ( python manage.py makemigrations). È quindi possibile migrare e dovrebbe funzionare ( python manage.py migrate)

Spero che sia d'aiuto. Naturalmente provalo in locale prima di provare in produzione per evitare brutte sorprese :)


8
che dire delle relazioni ManyToManyField ??
Tomcounsell,

1
@tomcounsell ottimo commento, presumo aggiungendo un modello specifico attraverso solo ai fini delle migrazioni. Per lasciare intatti i dati è necessaria una grande mole di lavoro ...
Wtower,

Poiché una relazione molti-a-molti è in genere solo una tabella con due chiavi esterne, da un punto di vista SQL è possibile applicare il trucco di questa risposta. Ma per raggiungere questo obiettivo solo tramite Django, un approccio che mi viene in mente sarebbe quello di rispondere alla risposta di @ozan, tranne per il fatto che il primo passo sarebbe duplicare le tabelle coinvolte nella relazione MTM (una versione dei duplicati in ogni app) , migra tutte le chiavi esterne nella nuova app e solo successivamente elimina i duplicati nella vecchia app. Disclaimer: non ho ancora testato :)
Arnaud P

15

Come l'ho fatto (testato su Django == 1.8, con postgres, quindi probabilmente anche 1.7)

Situazione

app1.YourModel

ma vuoi che vada a: app2.YourModel

  1. Copia YourModel (il codice) da app1 ad app2.
  2. aggiungi questo ad app2.YourModel:

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

  4. Una nuova migrazione (ad es. 0009_auto_something.py) viene effettuata in app2 con un'istruzione migrations.CreateModel (), sposta questa istruzione nella migrazione iniziale di app2 (ad es. 0001_initial.py) (sarà come se fosse sempre stata lì). E ora rimuovi la migrazione creata = 0009_auto_something.py

  5. Proprio come ti comporti, come app2.YourModel è sempre stato lì, ora rimuovi l'esistenza di app1.YourModel dalle tue migrazioni. Significato: commentare le istruzioni CreateModel e ogni regolazione o migrazione di dati utilizzata successivamente.

  6. E, naturalmente, ogni riferimento a app1.YourModel deve essere modificato in app2.YourModel attraverso il progetto. Inoltre, non dimenticare che tutte le possibili chiavi esterne di app1.YourModel nelle migrazioni devono essere modificate in app2.YourModel

  7. Ora se si esegue la migrazione di $ python manage.py, nulla è cambiato, anche quando si eseguono le migrazioni $ python manage.py, non è stato rilevato nulla di nuovo.

  8. Ora il tocco finale: rimuovi la classe Meta da app2.YourModel e fai $ python manage.py makemigrations app2 && python manage.py migra app2 (se guardi a questa migrazione vedrai qualcosa di simile :)

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

table = None, significa che prenderà il nome tabella predefinito, che in questo caso sarà app2_yourmodel.

  1. FATTO, con i dati salvati.

PS durante la migrazione vedrà che content_type app1.yourmodel è stato rimosso e può essere eliminato. Puoi dire di sì, ma solo se non lo usi. Nel caso in cui tu dipenda fortemente da esso per avere intatti gli FK con quel tipo di contenuto, non rispondere ancora sì o no, ma vai nel db quel tempo manualmente e rimuovi il contentype app2.yourmodel e rinomina l'app contenttype1. il tuo modello a app2.yourmodel, quindi continua rispondendo no.


3
Sebbene questa soluzione sia decisamente più "hacker" di @ ozan e ha sicuramente bisogno di più editing, ha funzionato bene per me (ed è OK per modificare le migrazioni - dovrebbero essere modificabili, secondo i documenti).
pgcd,

1
Probabilmente usa anche la app_label = 'app1'meta opzione.
Wtower,

Genio! Questo ha funzionato perfettamente per me nelle relazioni con ForeignKey. Suppongo che funzionerà anche per i campi ManyToMany.
Babken Vardanyan,

Ho seguito i tuoi passaggi ma il campo in alcuni modelli appartenenti all'app1 è costituito da una chiave esterna con una relazione ricorsiva con il modello (myModel) da spostare. Come field1 = models.ForeignKey('app1.myModel').quando migra, ricevo un ValueError che lo affermafield1 was declared with a lazy reference to 'app1.myModel' but app 'app1' doesn't provide model 'MyModel'
Deesha,

12

Ottengo migrazioni nervose di codifica manuale (come richiesto dalla risposta di Ozan ), quindi quanto segue combina le strategie di Ozan e Michael per ridurre al minimo la quantità di codifica manuale richiesta:

  1. Prima di spostare qualsiasi modello, assicurati di lavorare con una linea di base pulita eseguendo makemigrations.
  2. Sposta il codice per il Modello da app1aapp2
  3. Come raccomandato da @Michael, puntiamo il nuovo modello alla vecchia tabella del database usando l' db_tableopzione Meta sul "nuovo" modello:

    class Meta:
        db_table = 'app1_yourmodel'
  4. Corri makemigrations. Questo genererà CreateModeldentro app2e DeleteModeldentro app1. Tecnicamente, queste migrazioni si riferiscono alla stessa identica tabella e rimuovono (compresi tutti i dati) e ricreano la tabella.

  5. In realtà, non vogliamo (o non abbiamo bisogno) di fare nulla al tavolo. Abbiamo solo bisogno di Django per credere che il cambiamento sia stato fatto. Per la risposta di @ Ozan, la state_operationsbandiera SeparateDatabaseAndStatefa questo. Quindi inseriamo tutte le migrationsvoci IN ENTRAMBI I FILE DI MIGRAZIONI con SeparateDatabaseAndState(state_operations=[...]). Per esempio,

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

    diventa

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=[
            ...
            migrations.DeleteModel(
                name='YourModel',
            ),
            ...
        ])
    ]
  6. È inoltre necessario assicurarsi che la nuova CreateModelmigrazione "virtuale" dipenda da qualsiasi migrazione che abbia effettivamente creato o modificato la tabella originale . Ad esempio, se le nuove migrazioni sono app2.migrations.0004_auto_<date>(per Create) e app1.migrations.0007_auto_<date>(per Delete), la cosa più semplice da fare è:

    • Apri app1.migrations.0007_auto_<date>e copia la sua app1dipendenza (es ('app1', '0006...'),.). Questa è la migrazione "immediatamente precedente" app1e dovrebbe includere dipendenze da tutta la logica di costruzione del modello reale.
    • Apri app2.migrations.0004_auto_<date>e aggiungi la dipendenza che hai appena copiato nel suo dependencieselenco.

Se hai ForeignKeyrelazioni con il modello che stai spostando, quanto sopra potrebbe non funzionare. Questo accade perché:

  • Le dipendenze non vengono create automaticamente per le ForeignKeymodifiche
  • Non vogliamo includere le ForeignKeymodifiche, state_operationsquindi dobbiamo assicurarci che siano separate dalle operazioni della tabella.

NOTA: Django 2.2 ha aggiunto un avviso ( models.E028) che interrompe questo metodo. Potresti essere in grado di aggirare il problema con managed=Falsema non l'ho provato.

L'insieme "minimo" di operazioni differisce a seconda della situazione, ma la seguente procedura dovrebbe funzionare per la maggior parte / tutte le ForeignKeymigrazioni:

  1. COPIA il modello da app1a app2, imposta db_table, ma NON modificare alcun riferimento FK.
  2. Esegui makemigrationse avvolgi tutta la app2migrazione state_operations(vedi sopra)
    • Come sopra, aggiungi una dipendenza app2 CreateTableall'ultima app1migrazione
  3. Puntare tutti i riferimenti FK al nuovo modello. Se non stai usando riferimenti a stringa, sposta il vecchio modello in fondo a models.py(NON rimuoverlo) in modo che non competa con la classe importata.
  4. Esegui makemigrationsma NON avvolgere nulla state_operations(i cambiamenti dell'FK dovrebbero effettivamente avvenire). Aggiungi una dipendenza in tutte le ForeignKeymigrazioni (es. AlterField) CreateTableAlla migrazione in app2(avrai bisogno di questo elenco per il passaggio successivo, quindi tienili traccia). Per esempio:

    • Trova la migrazione che include CreateModeleg app2.migrations.0002_auto_<date>e copia il nome di quella migrazione.
    • Trova tutte le migrazioni che hanno un ForeignKey a quel modello (ad esempio, cercando app2.YourModeldi trovare migrazioni come:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
          ]
      
          operations = [
              migrations.AlterField(
                  model_name='relatedmodel',
                  name='fieldname',
                  field=models.ForeignKey(... to='app2.YourModel'),
              ),
          ]
    • Aggiungi la CreateModelmigrazione come dipendenza:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
              ('app2', '0002_auto_<date>'),
          ]  
  5. Rimuovere i modelli da app1

  6. Esegui makemigrationse avvolgi la app1migrazione state_operations.
    • Aggiungi una dipendenza a tutte le ForeignKeymigrazioni (cioè AlterField) dal passaggio precedente (può includere migrazioni in app1e app2).
    • Quando ho creato queste migrazioni, le DeleteTabledipendevano già dalle AlterFieldmigrazioni, quindi non avevo bisogno di applicarle manualmente (cioè Alterprima Delete).

A questo punto, Django è pronto. Il nuovo modello punta al vecchio tavolo e le migrazioni di Django lo hanno convinto che tutto è stato trasferito in modo appropriato. Il grande avvertimento (dalla risposta di @ Michael) è che ContentTypeviene creato un nuovo per il nuovo modello. Se si collega (ad esempio da ForeignKey) a tipi di contenuto, è necessario creare una migrazione per aggiornare la ContentTypetabella.

Volevo ripulire dopo me stesso (Meta opzioni e nomi delle tabelle) quindi ho usato la seguente procedura (da @Michael):

  1. Rimuovi la db_tablevoce Meta
  2. Eseguire di makemigrationsnuovo per generare la ridenominazione del database
  3. Modifica quest'ultima migrazione e assicurati che dipenda dalla DeleteTablemigrazione. Non sembra che dovrebbe essere necessario in quanto Deletedovrebbe essere puramente logico, ma se non ci sono errori (ad es. app1_yourmodelNon esiste).

Questo ha funzionato perfettamente, grazie! Non credo che la modifica dell'ultima migrazione sia importante poiché si trova comunque nella parte inferiore dell'albero delle dipendenze.
James Meakin,

1
Buona risposta! Penso che sia necessario aggiungere una parentesi di chiusura alle migrazioni.SeparateDatabaseAndState, giusto?
atm

Questo ha funzionato per me. Inoltre non ho modificato l'ultima migrazione (passaggio 3, l'ultima riga dell'intera risposta) come @JamesMeakin e funzionava ancora bene
Megawatt

nel secondo scenario, quello con gli FK, il secondo passo è fallito per me con un errore che ha senso:table_name: (models.E028) db_table 'table_name' is used by multiple models: app1.Model, app2.Model.
Mihai Zamfir

Ho usato la procedura un paio di volte. Se si confronta la documentazione per 2.2 ( docs.djangoproject.com/en/2.2/ref/checks ) e 2.1 ( docs.djangoproject.com/en/2.1/ref/checks ), è possibile vedere che è stata aggiunta in 2.2. Potrebbe essere possibile aggirare il problema managed=Falsema non sono in grado di controllare.
Claytond

1

Un'altra alternativa hacky se i dati non sono grandi o troppo complicati, ma comunque importanti da mantenere, è:

  • Ottieni infissi di dati usando manage.py dumpdata
  • Procedere per modellare correttamente le modifiche e le migrazioni, senza correlare le modifiche
  • Global sostituisce i dispositivi dal vecchio modello e i nomi delle app al nuovo
  • Caricare i dati utilizzando manage.py loaddata

1

Copiato dalla mia risposta a https://stackoverflow.com/a/47392970/8971048

Nel caso in cui sia necessario spostare il modello e non si abbia più accesso all'app (o non si desidera l'accesso), è possibile creare una nuova Operazione e considerare di creare un nuovo modello solo se il modello migrato non lo fa esistere.

In questo esempio sto passando "MyModel" da 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))
            ],
        ),
    ]

Si prega di non aggiungere la stessa risposta a più domande. Rispondi a quello migliore e contrassegna il resto come duplicati. Vedi È accettabile aggiungere una risposta duplicata a diverse domande?
Petter Friberg,

0

Questo è testato approssimativamente, quindi non dimenticare di eseguire il backup del tuo DB !!!

Ad esempio, ci sono due app: src_appe dst_app, vogliamo spostare il modello MoveMeda src_appa dst_app.

Crea migrazioni vuote per entrambe le app:

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

Supponiamo che le nuove migrazioni siano XXX1_src_app_newe XXX1_dst_app_new, le precedenti migrazioni principali siano XXX0_src_app_olde XXX0_dst_app_old.

Aggiungere un'operazione che rinomina la tabella per il MoveMemodello e rinomina la sua etichetta_app in ProjectState in XXX1_dst_app_new. Non dimenticare di aggiungere dipendenza dalla XXX0_src_app_oldmigrazione. La XXX1_dst_app_newmigrazione risultante è:

# -*- 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'),
    ]

Aggiungi dipendenza XXX1_dst_app_newa XXX1_src_app_new. XXX1_src_app_newè la migrazione no-op necessaria per assicurarsi che le src_appmigrazioni future vengano eseguite dopoXXX1_dst_app_new .

Sposta MoveMeda src_app/models.pya dst_app/models.py. Quindi eseguire:

python manage.py migrate

È tutto!


Nota che questo codice è probabilmente utile solo per django 1.7. Provare questo in Django 2.0 non funzionerà. Ciò significa anche che l'utilizzo di questo meccanismo per lo spostamento dei modelli aggiunge un sovraccarico di manutenzione all'aggiornamento della versione di django.
Paul in 't Hout,

0

Puoi provare quanto segue (non testato):

  1. sposta il modello da src_appadest_app
  2. migrare dest_app; assicurarsi che la migrazione dello schema dipenda dall'ultima src_appmigrazione ( https://docs.djangoproject.com/en/dev/topics/migrations/#migration-files )
  3. aggiungere una migrazione di dati a dest_app, che copia tutti i dati dasrc_app
  4. migrare src_app; assicurarsi che la migrazione dello schema dipenda dall'ultima migrazione (dati) di dest_app- ovvero la migrazione del passaggio 3

Nota che copierai l'intera tabella, invece di spostarla , ma in questo modo entrambe le app non devono toccare una tabella che appartiene all'altra app, che penso sia più importante.


0

Diciamo che stai spostando il modello TheModel da app_a ad app_b.

Una soluzione alternativa è quella di modificare manualmente le migrazioni esistenti. L'idea è che ogni volta che vedi un'operazione che modifica TheModel nelle migrazioni di app_a, copi quell'operazione alla fine della migrazione iniziale di app_b. E ogni volta che vedi un riferimento "app_a.TheModel" nelle migrazioni di app_a, lo cambi in "app_b.TheModel".

L'ho appena fatto per un progetto esistente, dove volevo estrarre un certo modello in un'app riutilizzabile. La procedura è andata bene. Immagino che le cose sarebbero molto più difficili se ci fossero riferimenti da app_b ad app_a. Inoltre, avevo una Meta.db_table definita manualmente per il mio modello che avrebbe potuto essere d'aiuto.

In particolare, finirai con una cronologia migratoria modificata. Questo non importa, anche se si dispone di un database con le migrazioni originali applicate. Se entrambe le migrazioni originali e riscritte finiscono con lo stesso schema del database, tale riscrittura dovrebbe essere OK.


0
  1. cambia i nomi dei vecchi modelli in 'nome_modello_oldo'
  2. makemigrations
  3. crea nuovi modelli denominati 'nome_modello_new' con relazioni identiche sui modelli correlati (ad es. il modello utente ora ha user.blog_old e user.blog_new)
  4. makemigrations
  5. scrivere una migrazione personalizzata che migra tutti i dati nelle nuove tabelle del modello
  6. testare al diavolo queste migrazioni confrontando i backup con le nuove copie di database prima e dopo aver eseguito le migrazioni
  7. quando tutto è soddisfacente, eliminare i vecchi modelli
  8. makemigrations
  9. cambia i nuovi modelli con il nome corretto 'nome_modello_nuovo' -> 'nome_modello'
  10. testare tutta la serie di migrazioni su un server di gestione temporanea
  11. abbassa il sito di produzione per alcuni minuti per eseguire tutte le migrazioni senza che gli utenti interferiscano

Fallo individualmente per ogni modello che deve essere spostato. Non consiglierei di fare ciò che dice l'altra risposta cambiando in numeri interi e di nuovo in chiavi esterne. È possibile che le nuove chiavi esterne siano diverse e che le righe possano avere ID diversi dopo le migrazioni e non volevo correre alcun rischio di ID non corrispondenti quando si ritorna a chiavi esterne.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.