Django
migrazioni
Ricerca…
Parametri
comando di django-admin | Dettagli |
---|---|
makemigrations <my_app> | Genera migrazioni per my_app |
makemigrations | Genera migrazioni per tutte le app |
makemigrations --merge | Risolvi i conflitti di migrazione per tutte le app |
makemigrations --merge <my_app> | Risolvi i conflitti di migrazione per my_app |
makemigrations --name <migration_name> <my_app> | Genera una migrazione per my_app con il nome migration_name |
migrate <my_app> | Applica le migrazioni in sospeso di my_app al database |
migrate | Applica tutte le migrazioni in sospeso al database |
migrate <my_app> <migration_name> | Applica o disattiva fino a migration_name |
migrate <my_app> zero | Annulla l'applicazione di tutte le migrazioni in my_app |
sqlmigrate <my_app> <migration_name> | Stampa l'SQL per la migrazione denominata |
showmigrations | Mostra tutte le migrazioni per tutte le app |
showmigrations <my_app> | Mostra tutte le migrazioni in my_app |
Lavorare con le migrazioni
Django usa le migrazioni per propagare le modifiche apportate ai tuoi modelli al tuo database. Il più delle volte django può generarli per te.
Per creare una migrazione, esegui:
$ django-admin makemigrations <app_name>
Questo creerà un file di migrazione nel sottomodulo di migration
di app_name
. La prima migrazione sarà denominata 0001_initial.py
, l'altra inizierà con 0002_
, quindi 0003
, ...
Se ometti <app_name>
questo creerà le migrazioni per tutti i tuoi INSTALLED_APPS
.
Per propagare le migrazioni al tuo database, esegui:
$ django-admin migrate <app_name>
Per mostrare tutte le tue migrazioni, esegui:
$ django-admin showmigrations app_name
app_name
[X] 0001_initial
[X] 0002_auto_20160115_1027
[X] 0003_somemodel
[ ] 0004_auto_20160323_1826
-
[X]
significa che la migrazione è stata propagata al tuo database -
[ ]
significa che la migrazione non è stata propagata al tuo database. Usa ladjango-admin migrate
didjango-admin migrate
per propagarlo
Chiama anche ripristinare le migrazioni, questo può essere fatto passando il nome della migrate command
. Dato l'elenco di migrazioni di cui sopra (mostrato da django-admin showmigrations
):
$ django-admin migrate app_name 0002 # Roll back to migration 0002
$ django-admin showmigrations app_name
app_name
[X] 0001_initial
[X] 0002_auto_20160115_1027
[ ] 0003_somemodel
[ ] 0004_auto_20160323_1826
Migrazioni manuali
A volte, le migrazioni generate da Django non sono sufficienti. Ciò è particolarmente vero quando si desidera effettuare migrazioni di dati .
Ad esempio, disponiamo di tale modello:
class Article(models.Model):
title = models.CharField(max_length=70)
Questo modello ha già dati esistenti e ora vuoi aggiungere uno SlugField
:
class Article(models.Model):
title = models.CharField(max_length=70)
slug = models.SlugField(max_length=70)
Hai creato le migrazioni per aggiungere il campo, ma ora ti piacerebbe impostare lo slug per tutti gli articoli esistenti, in base al loro title
.
Certo, potresti semplicemente fare qualcosa del genere nel terminale:
$ django-admin shell
>>> from my_app.models import Article
>>> from django.utils.text import slugify
>>> for article in Article.objects.all():
... article.slug = slugify(article.title)
... article.save()
...
>>>
Ma dovrai farlo in tutti i tuoi ambienti (ad esempio il tuo desktop dell'ufficio, il tuo laptop, ...), tutti i tuoi colleghi dovranno farlo anche tu, e dovrai pensarci su come mettere in scena e quando spingi vivere.
Per farlo una volta per tutte, lo faremo in una migrazione. Per prima cosa crea una migrazione vuota:
$ django-admin makemigrations --empty app_name
Questo creerà un file di migrazione vuoto. Aprilo, contiene uno scheletro di base. Supponiamo che la tua precedente migrazione sia stata denominata 0023_article_slug
e che questa sia denominata 0024_auto_20160719_1734
. Ecco cosa scriveremo nel nostro file di migrazione:
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-07-19 15:34
from __future__ import unicode_literals
from django.db import migrations
from django.utils.text import slugify
def gen_slug(apps, schema_editor):
# We can't import the Article model directly as it may be a newer
# version than this migration expects. We use the historical version.
Article = apps.get_model('app_name', 'Article')
for row in Article.objects.all():
row.slug = slugify(row.name)
row.save()
class Migration(migrations.Migration):
dependencies = [
('hosting', '0023_article_slug'),
]
operations = [
migrations.RunPython(gen_slug, reverse_code=migrations.RunPython.noop),
# We set `reverse_code` to `noop` because we cannot revert the migration
# to get it back in the previous state.
# If `reverse_code` is not given, the migration will not be reversible,
# which is not the behaviour we expect here.
]
Migrazioni false
Quando viene eseguita una migrazione, Django memorizza il nome della migrazione in una tabella django_migrations.
Crea e simula le migrazioni iniziali per lo schema esistente
Se la tua app ha già modelli e tabelle di database e non ha migrazioni. Per prima cosa crea le migrazioni iniziali per la tua app.
python manage.py makemigrations your_app_label
Ora false migrazioni iniziali come applicate
python manage.py migrate --fake-initial
Fake tutte le migrazioni in tutte le app
python manage.py migrate --fake
Migrazioni di app singole false
python manage.py migrate --fake core
File di migrazione singola falso
python manage.py migrate myapp migration_name
Nomi personalizzati per i file di migrazione
Utilizzare l' makemigrations --name <your_migration_name>
per consentire la denominazione delle migrazioni (s) anziché utilizzare un nome generato.
python manage.py makemigrations --name <your_migration_name> <app_name>
Risolvere i conflitti di migrazione
introduzione
A volte le migrazioni entrano in conflitto, con il risultato di rendere la migrazione non riuscita. Questo può accadere in un sacco di scenerio, tuttavia può verificarsi regolarmente durante lo sviluppo di un'app con un team.
I conflitti di migrazione comuni si verificano durante l'utilizzo del controllo del codice sorgente, soprattutto quando viene utilizzato il metodo funzione-per-ramo. Per questo scenario useremo un modello chiamato Reporter
con gli attributi name
e address
.
Due sviluppatori a questo punto svilupperanno una funzionalità, quindi entrambi avranno questa copia iniziale del modello Reporter
. Lo sviluppatore A aggiunge age
che risulta nel file 0002_reporter_age.py
. Lo sviluppatore B aggiunge un campo bank_account
che viene 0002_reporter_bank_account
in 0002_reporter_bank_account
. Una volta che questi sviluppatori uniscono il loro codice e tentano di migrare le migrazioni, si è verificato un conflitto di migrazione.
Questo conflitto si verifica perché queste migrazioni modificano entrambi lo stesso modello, Reporter
. Inoltre, i nuovi file iniziano entrambi con 0002.
Unione di migrazioni
Ci sono diversi modi per farlo. Quanto segue è nell'ordine consigliato:
La soluzione più semplice è eseguire il comando makemigrations con un flag --merge.
python manage.py makemigrations --merge <my_app>
Questo creerà una nuova migrazione per risolvere il conflitto precedente.
Quando questo file extra non è benvenuto nell'ambiente di sviluppo per motivi personali, un'opzione è quella di eliminare le migrazioni in conflitto. Quindi, è possibile eseguire una nuova migrazione utilizzando il normale comando
makemigrations
. Quando vengono scritte le migrazioni personalizzate, ad esempiomigrations.RunPython
, è necessario tenere conto dell'utilizzo di questo metodo.
Cambia un CharField in un ForeignKey
Prima di tutto, supponiamo che questo sia il tuo modello iniziale, all'interno di un'applicazione chiamata discography
:
from django.db import models
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
Ora, ti rendi conto che vuoi usare una ForeignKey per l'artista. Questo è un processo un po 'complesso, che deve essere fatto in diversi passaggi.
Passaggio 1, aggiungere un nuovo campo per ForeignKey, assicurandosi di contrassegnarlo come null (si noti che ora è incluso anche il modello a cui stiamo collegando):
from django.db import models
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
artist_link = models.ForeignKey('Artist', null=True)
class Artist(models.Model):
name = models.CharField(max_length=255)
... e creare una migrazione per questo cambiamento.
./manage.py makemigrations discography
Passaggio 2, compilare il nuovo campo. Per fare ciò, devi creare una migrazione vuota.
./manage.py makemigrations --empty --name transfer_artists discography
Una volta che hai questa migrazione vuota, vuoi aggiungere una singola operazione RunPython
ad essa per collegare i tuoi record. In questo caso, potrebbe assomigliare a questo:
def link_artists(apps, schema_editor):
Album = apps.get_model('discography', 'Album')
Artist = apps.get_model('discography', 'Artist')
for album in Album.objects.all():
artist, created = Artist.objects.get_or_create(name=album.artist)
album.artist_link = artist
album.save()
Ora che i tuoi dati vengono trasferiti nel nuovo campo, potresti effettivamente essere fatto e lasciare tutto come è, usando il nuovo campo artist_link
per tutto. Oppure, se vuoi fare un po 'di pulizia, vuoi creare altre due migrazioni.
Per la tua prima migrazione, vorrai cancellare il tuo campo originale, artist
. Per la tua seconda migrazione, rinomina il nuovo campo artist_link
con l' artist
.
Questo viene fatto in più passaggi per garantire che Django riconosca le operazioni correttamente.