---
title: "Come creare migrazioni di database"
version: 4.2
locale: it
source: https://docs.djangoproject.com/it/4.2/howto/writing-migrations/
canonical: https://djangodocs.dev/it/4.2/howto/writing-migrations/
---
# Come creare migrazioni di database

Questo documento spiega come strutturare e scrivere migrazioni di database per diversi scenari che potresti incontrare. Per materiale introduttivo sulle migrazioni, vedere [the topic guide](/it/4.2/topics/migrations/).

## Migrazioni dati e database multipli

Quando usi più database, potresti aver bisogno di capire se è necessario utilizzare una migrazione per un particolare database. Per esempio, puoi voler lanciare **solo** una migrazione verso uno specifico database.

Per fare ciò è possibile controllare l’alias della connessione del database all’interno di un’operazione `RunPython` guardando l’attributo `schema_editor.connection.alias`:

```
from django.db import migrations

def forwards(apps, schema_editor):
    if schema_editor.connection.alias != "default":
        return
    # Your migration code goes here

class Migration(migrations.Migration):
    dependencies = [
        # Dependencies to other migrations
    ]

    operations = [
        migrations.RunPython(forwards),
    ]
```

Puoi anche fornire suggerimenti che verranno passati al metodo [`allow_migrate()`](/it/4.2/topics/db/multi-db/#allow_migrate) del router di database come `**hints`:

*`myapp/dbrouters.py`*

```python
class MyRouter:
    def allow_migrate(self, db, app_label, model_name=None, **hints):
        if "target_db" in hints:
            return db == hints["target_db"]
        return True
```

Quindi, per sfruttare questo nelle tue migrazioni, procedi come segue:

```
from django.db import migrations

def forwards(apps, schema_editor):
    # Your migration code goes here
    ...

class Migration(migrations.Migration):
    dependencies = [
        # Dependencies to other migrations
    ]

    operations = [
        migrations.RunPython(forwards, hints={"target_db": "default"}),
    ]
```

Se la tua operazione `RunPython` o `RunSQL` interessa solo un modello, è buona norma passare `model_name` come suggerimento per renderlo il più trasparente possibile al router. Ciò è particolarmente importante per le app riutilizzabili e di terze parti.

## Migrazioni che aggiungono campi univoci

L’applicazione di una migrazione «plain» che aggiunge un campo univoco non annullabile a una tabella con righe esistenti genererà un errore poiché il valore utilizzato per popolare le righe esistenti viene generato una sola volta, interrompendo così il vincolo univoco.

Pertanto, è necessario eseguire i seguenti passaggi. In questo esempio, aggiungeremo un non-nullable [`UUIDField`](/it/4.2/ref/models/fields/#django.db.models.UUIDField) con un valore predefinito. Modifica il rispettivo campo in base alle tue esigenze.

- Aggiungi il campo al tuo modello con gli argomenti `default=uuid.uuid4` e `unique=True` (scegli un valore predefinito appropriato per il tipo di campo che stai aggiungendo).
- Esegui il comando [`makemigrations`](/it/4.2/ref/django-admin/#django-admin-makemigrations). Questo dovrebbe generare una migrazione con un’operazione `AddField`.
- Genera due file di migrazione vuoti per la stessa app eseguendo due volte `makemigrations myapp --empty`. Abbiamo rinominato i file di migrazione per assegnare loro nomi significativi negli esempi seguenti.
- Copia l’operazione `AddField` dalla migrazione generata automaticamente (il primo dei tre nuovi file) all’ultima migrazione, cambia `AddField` in `AlterField` e aggiungi le importazioni di `uuid` e `models`. Per esempio:

  *`0006_remove_uuid_null.py`*

  ```python
  # Generated by Django A.B on YYYY-MM-DD HH:MM
  from django.db import migrations, models
  import uuid

  class Migration(migrations.Migration):
      dependencies = [
          ("myapp", "0005_populate_uuid_values"),
      ]

      operations = [
          migrations.AlterField(
              model_name="mymodel",
              name="uuid",
              field=models.UUIDField(default=uuid.uuid4, unique=True),
          ),
      ]
  ```
- Modifica il primo file di migrazione. La classe di migrazione generata sarà simile a questa:

  *`0004_add_uuid_field.py`*

  ```python
  class Migration(migrations.Migration):
      dependencies = [
          ("myapp", "0003_auto_20150129_1705"),
      ]

      operations = [
          migrations.AddField(
              model_name="mymodel",
              name="uuid",
              field=models.UUIDField(default=uuid.uuid4, unique=True),
          ),
      ]
  ```

  Cambia `unique=True` in `null=True` – questo creerà il campo null intermedio e rinvierà la creazione del vincolo univoco fino a quando non avremo popolato valori univoci su tutte le righe.
- Nel primo file di migrazione vuoto, aggiungi una operazione [`RunPython`](/it/4.2/ref/migration-operations/#django.db.migrations.operations.RunPython) o [`RunSQL`](/it/4.2/ref/migration-operations/#django.db.migrations.operations.RunSQL) per generare un valore univoco (UUID nell’esempio) per ogni riga esistente. Aggiungi anche un import di `uuid`. Per esempio:

  *`0005_populate_uuid_values.py`*

  ```python
  # Generated by Django A.B on YYYY-MM-DD HH:MM
  from django.db import migrations
  import uuid

  def gen_uuid(apps, schema_editor):
      MyModel = apps.get_model("myapp", "MyModel")
      for row in MyModel.objects.all():
          row.uuid = uuid.uuid4()
          row.save(update_fields=["uuid"])

  class Migration(migrations.Migration):
      dependencies = [
          ("myapp", "0004_add_uuid_field"),
      ]

      operations = [
          # omit reverse_code=... if you don't want the migration to be reversible.
          migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
      ]
  ```
- Ora puoi applicare le migrazioni come al solito con il comando [`migrate`](/it/4.2/ref/django-admin/#django-admin-migrate) .

  Nota che si crea una race condition se permetti agli oggetti di essere creati mentre la migrazione gira. Gli oggetti creati dopo `AddField` e prima di `RunPython` avranno il loro `uuid` originale sovrascritto.

### Migrazioni «Non-atomic»

In un database che supporta le transazioni DDL (SQLite e PostgreSQL), le migrations sono eseguite di default all’interno di una transazione. Per casi d’uso quali migrations su grandi tabelle, potresti voler evitare l’esecuzione delle migrations all’interno di una transazione, configurando l’attributo `atomic` a `False`:

```
from django.db import migrations

class Migration(migrations.Migration):
    atomic = False
```

In tale migrazione, tutte le operazioni sono lanciate senza transazione. E” possibile eseguire parti della migrazione dentro una transazione usando [`atomic()`](/it/4.2/topics/db/transactions/#django.db.transaction.atomic) o passando `atomic=True` a `RunPython`.

Qui c’è un esempio di migrazione dei dati non atomica che aggiorna una grande tabella con piccoli passi automatici:

```
import uuid

from django.db import migrations, transaction

def gen_uuid(apps, schema_editor):
    MyModel = apps.get_model("myapp", "MyModel")
    while MyModel.objects.filter(uuid__isnull=True).exists():
        with transaction.atomic():
            for row in MyModel.objects.filter(uuid__isnull=True)[:1000]:
                row.uuid = uuid.uuid4()
                row.save()

class Migration(migrations.Migration):
    atomic = False

    operations = [
        migrations.RunPython(gen_uuid),
    ]
```

L’attributo `atomic` non ha effetto sui database che non supportano le transazioni DDL (per es. MySQL, Oracle). (Il supporto per le istruzioni [atomic DDL di MySQL](https://dev.mysql.com/doc/refman/en/atomic-ddl.html) si riferisce a singole istruzioni, piuttosto che a più istruzioni racchiuse in una transazione sulla quale si può fare roll back.)

## Controllo dell’ordine delle migrazioni

Django determina l’ordine in cui le migrazioni dovrebbero essere applicate non in base al nome del file di ogni migrazione, ma usando un grafo che usa due proprietà sulla classe `Migration`: `dependencies` e `run_before`.

Se hai usato il comando [`makemigrations`](/it/4.2/ref/django-admin/#django-admin-makemigrations) probabilmente hai già visto `dependencies` in azione perchè le migrazioni auto-generate lo hanno definito come parte del loro processo di creazione.

La proprietà `dependencies` viene dichiarata in questo modo:

```
from django.db import migrations

class Migration(migrations.Migration):
    dependencies = [
        ("myapp", "0123_the_previous_migration"),
    ]
```

Generalmente questo basta, ma di volta in volta potresti aver bisogno di assicurarti che le tue migrazioni girino *prima* di altre migrazioni. Questo torna utile, ad esempio, per fare in modo che le migrazioni delle app di terze parti girino *dopo* i rimpiazzi sul tuo [`AUTH_USER_MODEL`](/it/4.2/ref/settings/#std-setting-AUTH_USER_MODEL).

Per ottenere ciò, inserisci tutte le migrazioni che dovrebbero dipendere dalla tua nell’attributo `run_before` nella tua classe `Migration`:

```
class Migration(migrations.Migration):
    ...

    run_before = [
        ("third_party_app", "0001_do_awesome"),
    ]
```

È preferibile usare `dipendenze` su `run_before` quando possibile. Dovresti usare `run_before` solo se non è desiderabile o non pratico specificare `dependencies` nella migrazione che vuoi eseguire dopo quella che stai scrivendo.

## Migrazione dei dati tra app

È possibile utilizzare una migrazione dei dati per spostare i dati da un’applicazione ad un’altra.

Se prevedi di rimuovere la vecchia app in un secondo momento, dovrai impostare la proprietà `dependencies` in base al fatto che la vecchia app sia installata o meno. Altrimenti, avrai le dipendenze mancanti dopo aver disinstallato la vecchia app. Allo stesso modo, dovrai catturare [`LookupError`](https://docs.python.org/3/library/exceptions.html#LookupError) nella chiamata `apps.get_model()` che recupera i modelli dalla vecchia app. Questo approccio ti consente di distribuire il tuo progetto ovunque senza prima installare e quindi disinstallare la vecchia app.

Ecco un esempio di migrazione:

*`myapp/migrations/0124_move_old_app_to_new_app.py`*

```python
from django.apps import apps as global_apps
from django.db import migrations

def forwards(apps, schema_editor):
    try:
        OldModel = apps.get_model("old_app", "OldModel")
    except LookupError:
        # The old app isn't installed.
        return

    NewModel = apps.get_model("new_app", "NewModel")
    NewModel.objects.bulk_create(
        NewModel(new_attribute=old_object.old_attribute)
        for old_object in OldModel.objects.all()
    )

class Migration(migrations.Migration):
    operations = [
        migrations.RunPython(forwards, migrations.RunPython.noop),
    ]
    dependencies = [
        ("myapp", "0123_the_previous_migration"),
        ("new_app", "0001_initial"),
    ]

    if global_apps.is_installed("old_app"):
        dependencies.append(("old_app", "0001_initial"))
```

Potresti non fare nulla (come nell’esempio sopra) o rimuovere alcuni o tutti i dati dalla nuova applicazione. Regola di conseguenza il secondo argomento dell’operazione [`RunPython`](/it/4.2/ref/migration-operations/#django.db.migrations.operations.RunPython).

## Modifica di un `ManyToManyField` per utilizzare un modello `through`

Se modifichi una [`ManyToManyField`](/it/4.2/ref/models/fields/#django.db.models.ManyToManyField) per usare un modello `through`, la migrazione predefinita cancellerà la tabella esistente e ne creerà una nuova, perdendo le relazioni esistenti. Per evitare ciò, puoi utilizzare [`SeparateDatabaseAndState`](/it/4.2/ref/migration-operations/#django.db.migrations.operations.SeparateDatabaseAndState) per rinominare la tabella esistente con il nuovo nome della tabella, comunicando al rilevatore automatico di migrazione che il nuovo modello è stato creato. Puoi controllare il nome della tabella esistente tramite [`sqlmigrate`](/it/4.2/ref/django-admin/#django-admin-sqlmigrate) o [`dbshell`](/it/4.2/ref/django-admin/#django-admin-dbshell). Puoi controllare il nuovo nome della tabella attraverso la proprietà `_meta.db_table` del modello. Il tuo nuovo modello `through` dovrebbe usare gli stessi nomi per `ForeignKey`s di Django. Inoltre, se sono necessari campi aggiuntivi, dovrebbero essere aggiunti nelle operazioni dopo [`SeparateDatabaseAndState`](/it/4.2/ref/migration-operations/#django.db.migrations.operations.SeparateDatabaseAndState).

Per esempio, se avessimo un modello `Book` con un `ManyToManyField` collegato a `Author`, potremmo aggiungere un modello completo `AuthorBook` con un nuovo campo `is_primary`, come:

```
from django.db import migrations, models
import django.db.models.deletion

class Migration(migrations.Migration):
    dependencies = [
        ("core", "0001_initial"),
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=[
                # Old table name from checking with sqlmigrate, new table
                # name from AuthorBook._meta.db_table.
                migrations.RunSQL(
                    sql="ALTER TABLE core_book_authors RENAME TO core_authorbook",
                    reverse_sql="ALTER TABLE core_authorbook RENAME TO core_book_authors",
                ),
            ],
            state_operations=[
                migrations.CreateModel(
                    name="AuthorBook",
                    fields=[
                        (
                            "id",
                            models.AutoField(
                                auto_created=True,
                                primary_key=True,
                                serialize=False,
                                verbose_name="ID",
                            ),
                        ),
                        (
                            "author",
                            models.ForeignKey(
                                on_delete=django.db.models.deletion.DO_NOTHING,
                                to="core.Author",
                            ),
                        ),
                        (
                            "book",
                            models.ForeignKey(
                                on_delete=django.db.models.deletion.DO_NOTHING,
                                to="core.Book",
                            ),
                        ),
                    ],
                ),
                migrations.AlterField(
                    model_name="book",
                    name="authors",
                    field=models.ManyToManyField(
                        to="core.Author",
                        through="core.AuthorBook",
                    ),
                ),
            ],
        ),
        migrations.AddField(
            model_name="authorbook",
            name="is_primary",
            field=models.BooleanField(default=False),
        ),
    ]
```

## Modifica di un modello non gestito in gestito

Se desideri modificare un modello non gestito ([`managed=False`](/it/4.2/ref/models/options/#django.db.models.Options.managed)) in gestito, devi rimuovere `managed=False` e generare una migrazione prima di creare un altro schema -modifiche correlate al modello, poiché le modifiche allo schema che appaiono nella migrazione che contiene l’operazione di modifica di `Meta.managed` potrebbero non essere applicate.
