Domanda

Sto pianificando di rinominare diversi modelli in un progetto Django esistente in cui ci sono molti altri modelli che hanno relazioni chiave straniere con i modelli che vorrei rinominare. Sono abbastanza sicuro che richiederà più migrazioni, ma non sono sicuro della procedura esatta.

Diciamo che inizio con i seguenti modelli all'interno di un'app Django chiamata myapp:

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()
.

Voglio rinominare il modello Foo perché il nome non ha senso e sta causando confusione nel codice e generacodicitagcode renderebbe un nome molto più chiaro.

Da quello che ho letto nella documentazione di sviluppo Django, sto assumendo la seguente strategia di migrazione:

STEP 1

Modifica Bar:

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_ridonkulous = models.BooleanField()
.

Nota Il nome del campo models.py per AnotherModel non cambia, ma la relazione viene aggiornata al modello foo. Il mio ragionamento è che non dovrei cambiare troppo contemporaneamente e che se avessi cambiato questo nome di campo in Bar rischiare di perdere i dati in quella colonna.

STEP 2

Crea una migrazione vuota:

python manage.py makemigrations --empty myapp
.

STEP 3

Modificare la classe bar nel file di migrazione creato nel passaggio 2 per aggiungere l'operazione Migration all'elenco operazioni:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]
.

STEP 4

Applicare la migrazione:

python manage.py migrate
.

STEP 5

Modifica i nomi dei campi correlati in RenameModel:

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()
.

STEP 6

Crea un'altra migrazione vuota:

python manage.py makemigrations --empty myapp
.

STEP 7

Modificare la classe models.py nel file di migrazione creato nel passaggio 6 per aggiungere le operazioni Migration per eventuali nomi di campo correlati all'elenco delle operazioni:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_rename_fields'),  # <-- is this okay?
    ]

    operations = [
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]
.

STEP 8

Applicare la 2a migrazione:

python manage.py migrate
.


.

Oltre ad aggiornare il resto del codice (viste, moduli, ecc.) Per riflettere i nuovi nomi delle variabili, è fondamentalmente come funzionerà la nuova funzionalità di migrazione?

Inoltre, questo sembra un sacco di passi. Le operazioni di migrazione possono essere condensate in qualche modo?

Grazie!

È stato utile?

Soluzione

Quindi quando ho provato questo, sembra che tu possa condensare il passaggio 3 - 7:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'), 
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar'),
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]
.

È possibile ottenere alcuni errori se non aggiorni i nomi in cui è importato E.G.admin.py e persino file di migrazione anziani (!).

Aggiornamento : AS Ceasaro Menzioni, versioni più recenti di Django sono solitamente in grado di rilevare e chiedere se un modello viene rinominato.Quindi prova prima manage.py makemigrations e quindi controllare il file di migrazione.

Altri suggerimenti

All'inizio, ho pensato che il metodo di FID ha funzionato per me perché la migrazione ha funzionato bene fino al passaggio 4. Tuttavia, i cambiamenti impliciti "WnsoryKeyfield (Foo)" in "ForeignKeyField (bar)" non è stato correlato in nessuna migrazione. Questo è il motivo per cui la migrazione non è riuscita quando volevo rinominare i campi di relazione (Passaggio 5-8). Ciò potrebbe essere dovuto al fatto che il mio "trombedel" e "entanothermodel" vengono spediti in altre app nel mio caso.

Così sono riuscito a rinominare i miei modelli e campi di relazione facendo i seguenti passaggi seguenti:

Ho adattato il metodo da Questo e in particolare il trucco di otranzer.

Allora come Faber, diciamo che abbiamo in MyApp :

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)
.

e in myotherapp :

class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()
.

Step 1:

Trasforma ogni Onetoonefield (Foo) o ForeignKeyfield (foo) in Integerfield (). (Questo manterrà l'ID dell'oggetto Foo correlato come valore di Integerfield).

class AnotherModel(models.Model):
    foo = models.IntegerField()
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.IntegerField()
    is_ridonkulous = models.BooleanField()
.

quindi

python manage.py makemigrations

python manage.py migrate
.

Step 2: (come il passaggio 2-4 dal fibato)

Modifica il nome del modello

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)
.

Crea una migrazione vuota:

python manage.py makemigrations --empty myapp
.

Allora modifica come:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]
.

Alla fine

python manage.py migrate
.

Step 3:

Trasforma il tuo intero campo () nel loro precedenteKeyKeryfield o Onetoonefield precedente ma con il nuovo modello della barra. (Il precedente campo intero memorizzava l'ID, quindi Django capisce e ristabilire la connessione, che è fresca.)

class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_ridonkulous = models.BooleanField()
.

Allora fai:

python manage.py makemigrations 
.

Molto importantemente, in questo passaggio è necessario modificare ogni nuova migrazione e aggiungere la dipendenza dalle migrazioni Renamemodel Foo-> Bar. Quindi se sia a un trombedel che nell'etannothermodel sono in MyOtherapp la migrazione creata in MyOtherapp deve assomigliare a questo:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '00XX_the_migration_of_myapp_with_renamemodel_foo_bar'),
        ('myotherapp', '00xx_the_migration_of_myotherapp_with_integerfield'),
    ]

    operations = [
        migrations.AlterField(
            model_name='anothermodel',
            name='foo',
            field=models.ForeignKey(to='myapp.Bar'),
        ),
        migrations.AlterField(
            model_name='yetanothermodel',
            name='foo',
            field=models.ForeignKey(to='myapp.Bar')
        ),
    ]
.

quindi

python manage.py migrate
.

Step 4:

Alla fine puoi rinominare i tuoi campi

class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar) <------- Renamed fields
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar) <------- Renamed fields
    is_ridonkulous = models.BooleanField()
.

e quindi eseguire la ridenominazione automatica

python manage.py makemigrations
.

(Django dovrebbe chiederti se effettivamente ribattezzato il modelloName, dì Sì)

python manage.py migrate
.

E questo è!

funziona su django1.8

Avevo bisogno di fare la stessa cosa.Ho cambiato il modello tutto in una volta (cioè, passo 1 e passaggio 5 insieme).Quindi ha creato una migrazione dello schema, ma ha modificato per essere questo:

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.rename_table('Foo','Bar')

    def backwards(self, orm):
        db.rename_table('Bar','Foo')
.

Questo ha funzionato perfettamente.Tutti i miei dati esistenti si sono presentati, tutte le altre tabelle referenziate barra fine.

Da qui: https:// hanmir.wordpress.com/2012/08/30/rename-model-django-south-migrazione/

Per Django 1.10, sono riuscito a modificare due nomi di classe del modello (incluso un tasto europeo e con i dati) semplicemente eseguendo makemigrations, quindi migrare per l'app.Per il passo dei Makemigrations, ho dovuto confermare che volevo cambiare i nomi delle tabelle.Migrare i nomi delle tabelle senza problemi.

Poi ho cambiato il nome del campo delKey ForeignO per abbinare, e di nuovo è stato chiesto da Makemigrations per confermare che volevo cambiare il nome.Migrare rispetto al cambiamento.

Quindi ho preso questo in due passaggi senza alcun editing di file speciali.Ho ricevuto errori all'inizio perché ho dimenticato di cambiare il file admin.py, come menzionato da @Wasibigeek.

Ho anche affrontato il problema come v.thorey descritto e ha scoperto che il suo approccio è molto utile, ma può essere condensato in minori passaggi che sono effettivamente passati da 5 a 8 come fibati descritti senza fase 1 a 4 tranne che il passaggio 7 deve essereModificato come il mio passaggio sottostante 3. I passaggi generali sono come segue:

Step 1: Modifica i nomi dei campi correlati in modelli.py

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()
.

Step 2: Creare una migrazione vuota

python manage.py makemigrations --empty myapp
.

STEP 3: Modificare la classe di migrazione nel file di migrazione creato nel passaggio 2

class Migration(migrations.Migration):

dependencies = [
    ('myapp', '0001_initial'), 
]

operations = [
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.RenameModel('Foo', 'Bar'),
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.RenameField('AnotherModel', 'foo', 'bar'),
    migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
.

Step 4: Applicare la migrazione

python manage.py migrate
.

Fatto

P.S.Ho provato questo approccio su Django 1.9

Sto usando Django versione 1.9.4

Ho seguito i seguenti passaggi: -

Ho appena rinominato il modello Oldname a NewName Esegui python manage.py makemigrations.Ti chiederà Did you rename the appname.oldName model to NewName? [y/N] Seleziona Y

Esegui python manage.py migrate e ti chiederà

I seguenti tipi di contenuto sono stantio e devono essere eliminati:

appname | oldName
appname | NewName
.

anche gli oggetti relativi a questi tipi di contenuto da parte di una chiave esterna essere cancellatoSei sicuro di voler eliminare questi tipi di contenuto? Se non sei sicuro, rispondi a 'no'.

Type 'yes' to continue, or 'no' to cancel: Select No
.

Rinominare e migrare tutti i dati esistenti alla nuova tabella denominata per me.

Sfortunatamente, ho trovato problemi (ogni Django 1.x) con la migrazione di rinomina che lasciano i vecchi nomi di tabelle nel database.

Django non prova nemmeno nulla sul vecchio tavolo, rinomina solo il suo modello. Lo stesso problema con le chiavi estere e gli indici in generale - cambiamenti non sono tracciati correttamente da Django.

La soluzione più semplice (soluzione workaround):

class Foo(models.Model):
     name = models.CharField(unique=True, max_length=32)
     ...
Bar = Foo  # and use Bar only
.

La soluzione reale (un modo semplice per cambiare tutto Indici, vincoli, trigger, nomi, ecc. In 2 commit, ma piuttosto per più piccoli Tabelle):

Commit A:

    .
  1. Crea il modello stesso come vecchio
  2. # deprecated - TODO: TO BE REMOVED
    class Foo(model.Model):
        ...
    
    class Bar(model.Model):
        ...
    
    .
    1. Codice interruttore per lavorare con nuovo modello Bar solo. (comprese tutte le relazioni sullo schema)
    2. In Migrazione preparare RunPython, che copia i dati da Foo a Bar (compreso id di foo)

      1. Ottimizzazione opzionale (se necessario per tavole maggiori)
      2. Commit B: (nessuna fretta, fallo quando un'intera squadra viene migrata)

          .
        1. Goccia sicura del vecchio modello Foo

        2. .

          Ulteriori pulizie:

            .
          • Squash su migrazioni

          .

          Bug in Django:

Avevo bisogno di rinominare un paio di tavoli.Ma solo un modello Rinomina è stato notato da Django.Questo è successo perché Django Itera in aggiunta, quindi rimossi i modelli.Per ogni coppia, controlla se sono della stessa app e hanno campi identici .Solo una tabella non aveva chiavi straniere per le tabelle da rinominare (tasti stranieri contengono il nome della classe del modello, come ti ricordi).In altre parole, solo una tabella non aveva cambi di campo.Ecco perché è stato notato.

Quindi, la soluzione è rinominare una tabella alla volta, modificando il nome del modello di classe in models.py, possibilmente views.py e fare una migrazione.Dopodiché ispezionare il tuo codice per altri riferimenti (nomi di classe del modello, nomi correlati (query), nomi variabili).Fai una migrazione, se necessario.Quindi, opzionalmente combina tutte queste migrazioni in una (assicurati di copiare anche le importazioni).

Farei parole @CeasAro, la mia sul suo commento su questo Risposta .

Le versioni più recenti di Django possono rilevare modifiche e chiedere di ciò che è stato fatto. Vorrei anche aggiungere che Django potrebbe mescolare l'ordine di esecuzione di alcuni comandi migratori.

Sarebbe saggio applicare piccole modifiche e eseguire makemigrations e migrate e se l'errore si verifica il file di migrazione può essere modificato.

Alcune righe L'ordine di esecuzione può essere modificato per evitare errori.

Just wanted to confirm and add upon ceasaro comment. Django 2.0 seems to do this automatically now.

I'm on Jango 2.2.1, all I had to do what to rename the model and run makemigrations.

Here it asks if I had renamed the specific class from A to B, I chose yes and ran migrate and all seems to work.

Note I did not rename the old model name in any files inside the project/migrations folder.

If you are using a good IDE like PyCharm you can right click on the model name and do a refactor -> rename. This saves you the trouble of going through all your code that references the model. Then run makemigrations and migrate. Django 2+ will simply confirm name change.

I upgraded Django from version 10 to version 11:

sudo pip install -U Django

(-U for "upgrade") and it solved the problem.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top