2015-09-20 15 views
20

Sono curioso di sapere come altri sviluppatori di django gestiscono più rami di codice (in git per esempio) con le migrazioni.migrazioni di django - flusso di lavoro con più rami di sviluppo

Il mio problema è il seguente: - abbiamo più rami caratteristica in git, alcuni di loro con le migrazioni Django (alcuni dei quali campi alterare, o la rimozione del tutto) - quando passo rami (con git checkout some_other_branch) il database non riflette sempre il nuovo codice, quindi corro errori "casuali", in cui una colonna della tabella db non esiste più, ecc ...

In questo momento, faccio semplicemente cadere il db e lo ricrei, ma significa Devo ricreare un sacco di dati fittizi per riavviare il lavoro. Posso usare le fixture, ma è necessario tenere traccia di quali dati vanno dove, è un po 'una seccatura.

C'è un modo buono/pulito di trattare questo caso d'uso? Sto pensando che uno script di hook git post-checkout potrebbe eseguire le migrazioni necessarie, ma non so nemmeno se i rollback di migrazione sono possibili.

+2

Penso che @ eliot-berriot copra la maggior parte degli scenari. In realtà mi sono ispirato a questo numero per scrivere questo articolo in cui suggerisco una proposta: [Cosa mi infastidisce davvero delle migrazioni di Django] (https://cheesecakelabs.com/blog/really-annoys-django-migrations/?utm_source=stackoverflow&utm_medium= bernardo-domanda & utm_campaign = blog% 20 & utm_content = what-davvero-infastidisce-me-about-django-migrazioni). E ha iniziato questa lib con una proposta di hook git post-checkout: [django-nomad] (https://github.com/CheesecakeLabs/django-nomad). Cosa ne pensi? – bsmaniotto

risposta

11

Il rollback delle migrazioni è possibile e generalmente gestito automaticamente da Django.

Considerando il seguente modello:

class MyModel(models.Model): 
    pass 

Se si esegue python manage.py makemigrations myapp, genererà lo script di migrazione iniziale. È possibile eseguire python manage.py migrate myapp 0001 per applicare questa migrazione iniziale.

Se dopo che si aggiunge un campo al modello:

class MyModel(models.Model):  
    my_field = models.CharField() 

rigenerare una nuova migrazione, e applicarlo, è ancora possibile tornare allo stato iniziale. Basta eseguire python manage.py migrate myapp 0001 e l'ORM andrà indietro, rimuovendo il nuovo campo.

È più difficile quando si gestiscono le migrazioni dei dati, perché è necessario scrivere il codice forward e backward. Considerando una migrazione vuoto creato tramite python manage.py makemigrations myapp --empty, vi ritroverete con qualcosa di simile:

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

from django.db import models, migrations 

def forward(apps, schema_editor): 
    # load some data 
    MyModel = apps.get_model('myapp', 'MyModel') 

    while condition: 
     instance = MyModel() 
     instance.save() 

def backward(apps, schema_editor): 
    # delete previously loaded data 
    MyModel = apps.get_model('myapp', 'MyModel') 

    while condition: 
     instance = MyModel.objects.get(myargs) 
     instance.delete() 

class Migration(migrations.Migration): 

    dependencies = [ 
     ('myapp', '0003_auto_20150918_1153'), 
    ] 

    operations = [ 
     migrations.RunPython(forward, backward), 
    ] 

per Pure migrazioni di caricamento dei dati, di solito non è necessario la migrazione a ritroso. Ma quando si modifica lo schema e si aggiornano le righe esistenti,
(come la conversione di tutti i valori in una colonna in slug), in genere è necessario scrivere il passaggio all'indietro.

Nel nostro team, cerchiamo di evitare di lavorare sugli stessi modelli allo stesso tempo per evitare collisioni. Se non è possibile, e si creano due migrazioni con lo stesso numero (es. 0002), è ancora possibile rinominare uno di questi per modificare l'ordine in cui verranno applicati (ricordarsi anche di aggiornare l'attributo sul classe di migrazione al tuo nuovo ordine).

Se si finisce per lavorare sugli stessi campi del modello allo stesso tempo nelle caratteristiche diverse, sarete comunque in difficoltà, ma può significa queste caratteristiche sono correlate e devono essere maneggiati insieme in un unico ramo.

Per la parte git-ganci, è probabilmente possibile scrivere qualcosa, supponendo che il sono sul ramo mybranch e voler controllare un altro ramo caratteristica myfeature:

  1. Poco prima di passare, si discarica l'elenco dei attualmente migrazioni applicata in un file temporaneo mybranch_database_state.txt
  2. Quindi, si applica myfeature migrazioni filiali, se del caso
  3. Poi, quando il controllo indietro mybranch, si riapplica la tua precedente stato del database guardando al file di dettagli.

Tuttavia, sembra un po 'hacker per me, e probabilmente sarebbe davvero difficile da gestire correttamente tutti gli scenari: rebasing, la fusione, cherry-picking, ecc

Gestione dei conflitti migrazioni quando sembra mi sembra più facile.

4

Non ho una buona soluzione a questo, ma sento il dolore.

Un gancio post-checkout sarà troppo tardi. Se ti trovi nel ramo A e controlli il ramo B, e B ha meno migrazioni di A, le informazioni di rollback sono solo in A e devono essere eseguite prima del checkout.

Ho riscontrato questo problema saltando tra diversi commit cercando di individuare l'origine di un bug. Il nostro database (anche in fase di sviluppo) è enorme, quindi non è pratico cadere e ricreare.

sto immaginando un wrapper per git-checkout che:

  1. prende atto della recente di migrazione per ciascuna della vostra INSTALLED_APPS
  2. Looks nel ramo richiesto e prende atto delle recenti migrazioni ci
  3. Per ogni app dove le migrazioni al n. 1 sono più avanti rispetto alla n. 2, migrare alla migrazione più alta in # 2
  4. Scopri il nuovo ramo
  5. Per ogni app in cui le migrazioni in # 2 erano annuncio di # 1, migrare in avanti

Una semplice questione di programmazione!

Problemi correlati