# Django 6.0.7 documentation

# Så här skapar du databasmigreringar

Detta dokument förklarar hur man strukturerar och skriver databasmigreringar för olika scenarier som du kan stöta på. För inledande material om migreringar, se the topic guide.

## Datamigreringar och flera databaser

När du använder flera databaser kan du behöva ta reda på om du ska köra en migrering mot en viss databas eller inte. Du kanske till exempel vill köra en migrering endast på en viss databas.

För att göra det kan du kontrollera databasanslutningens alias i en `RunPython`-operation genom att titta på attributet `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),
        ]

You can also provide hints that will be passed to the `allow_migrate()` method of database routers as `**hints`:

`myapp/dbrouters.py`

    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

Gör sedan följande för att utnyttja detta i dina migreringar:

    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"}),
        ]

Om din `RunPython` eller `RunSQL` operation bara påverkar en modell är det god praxis att skicka `model_name` som en ledtråd för att göra det så transparent som möjligt för routern. Detta är särskilt viktigt för återanvändbara appar och tredjepartsappar.

## Migreringar som lägger till unika fält

Om du använder en ”vanlig” migrering som lägger till ett unikt icke-nullbart fält i en tabell med befintliga rader kommer det att uppstå ett fel eftersom det värde som används för att fylla i befintliga rader genereras endast en gång, vilket bryter den unika begränsningen.

Därför bör följande steg vidtas. I det här exemplet lägger vi till ett icke-nullbart `UUIDField` med ett standardvärde. Modifiera respektive fält efter dina behov.

- Lägg till fältet i din modell med argumenten `default=uuid.uuid4` och `unique=True` (välj en lämplig standard för den typ av fält du lägger till).

- Kör kommandot `makemigrations`. Detta bör generera en migrering med en `AddField` operation.

- Generera två tomma migreringsfiler för samma app genom att köra `makemigrations myapp --empty` två gånger. Vi har döpt om migreringsfilerna så att de får meningsfulla namn i exemplen nedan.

- Kopiera åtgärden `AddField` från den autogenererade migreringen (den första av de tre nya filerna) till den sista migreringen, ändra `AddField` till `AlterField` och lägg till import av `uuid` och `models`. Ett exempel:

  `0006_remove_uuid_null.py`

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

- Redigera den första migreringsfilen. Den genererade migreringsklassen bör se ut ungefär så här:

  `0004_add_uuid_field.py`

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

  Ändra `unique=True` till `null=True` - detta kommer att skapa det mellanliggande null-fältet och skjuta upp skapandet av den unika begränsningen tills vi har fyllt i unika värden på alla rader.

- I den första tomma migreringsfilen lägger du till en `RunPython` eller `RunSQL` operation för att generera ett unikt värde (UUID i exemplet) för varje befintlig rad. Lägg också till en import av `uuid`. För att ta ett exempel:

  `0005_populate_uuid_values.py`

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

- Nu kan du tillämpa migreringarna som vanligt med kommandot `migrate`.

  Observera att det finns ett tävlingsförhållande om du tillåter att objekt skapas medan denna migrering körs. Objekt som skapas efter `AddField` och före `RunPython` kommer att få sina ursprungliga `uuid` överskrivna.

### Icke-atomiska migreringar

På databaser som stöder DDL-transaktioner (SQLite och PostgreSQL) kommer migreringar att köras i en transaktion som standard. För användningsfall som att utföra datamigreringar på stora tabeller kanske du vill förhindra att en migrering körs i en transaktion genom att ställa in attributet `atomic` till `False`:

    from django.db import migrations

    class Migration(migrations.Migration):
        atomic = False

Within such a migration, all operations are run without a transaction. It’s possible to execute parts of the migration inside a transaction using `atomic()` or by passing `atomic=True` to `RunPython`.

Här är ett exempel på en icke-atomisk datamigrering som uppdaterar en stor tabell i mindre satser:

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

Attributet `atomic` har ingen effekt på databaser som inte stöder DDL-transaktioner (t.ex. MySQL, Oracle). (MySQL:s atomic DDL statement support hänvisar till enskilda uttalanden snarare än flera uttalanden som är insvepta i en transaktion som kan rullas tillbaka)

## Kontroll av migrationsordningen

Django bestämmer i vilken ordning migreringar ska tillämpas, inte genom filnamnet för varje migrering, utan genom att bygga en graf med hjälp av två egenskaper för klassen `Migration`: `dependencies` och `run_before`.

Om du har använt kommandot `makemigrations` har du förmodligen redan sett `dependencies` i aktion eftersom automatiskt skapade migreringar har detta definierat som en del av deras skapandeprocess.

Egenskapen `dependencies` deklareras på följande sätt:

    from django.db import migrations

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

Vanligtvis räcker det, men ibland kan du behöva se till att din migrering körs före andra migreringar. Detta är till exempel användbart för att få migreringar av tredjepartsappar att köras efter din `AUTH_USER_MODEL`-ersättning.

För att uppnå detta, placera alla migreringar som bör bero på din i `run_before`-attributet på din `Migration`-klass:

    class Migration(migrations.Migration):
        ...

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

Använd hellre `dependencies` än `run_before` när det är möjligt. Du bör endast använda `run_before` om det inte är önskvärt eller opraktiskt att ange `dependencies` i den migrering som du vill köra efter den du skriver.

## Migrering av data mellan appar från tredje part

Du kan använda en datamigrering för att flytta data från en tredjepartsapplikation till en annan.

Om du planerar att ta bort den gamla appen senare måste du ställa in egenskapen `dependencies` baserat på om den gamla appen är installerad eller inte. Annars kommer du att sakna beroenden när du avinstallerar den gamla appen. På samma sätt måste du fånga `LookupError` i anropet `apps.get_model()` som hämtar modeller från den gamla appen. Med det här tillvägagångssättet kan du distribuera ditt projekt var som helst utan att först installera och sedan avinstallera den gamla appen.

Här är ett exempel på en migrering:

`myapp/migrations/0124_move_old_app_to_new_app.py`

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

Fundera också på vad du vill ska hända när migreringen inte tillämpas. Du kan antingen inte göra någonting (som i exemplet ovan) eller ta bort vissa eller alla data från den nya applikationen. Justera det andra argumentet i `RunPython`-operationen i enlighet med detta.

## Ändra en `ManyToManyField` så att den använder en `through`-modell

Om du ändrar en `ManyToManyField` för att använda en `through`-modell, kommer standardmigreringen att radera den befintliga tabellen och skapa en ny, vilket innebär att befintliga relationer går förlorade. För att undvika detta kan du använda `SeparateDatabaseAndState` för att byta namn på den befintliga tabellen till det nya tabellnamnet samtidigt som du meddelar migreringsautodetektorn att den nya modellen har skapats. Du kan kontrollera det befintliga tabellnamnet och begränsningsnamnet genom `sqlmigrate` eller `dbshell`. Du kan kontrollera det nya tabellnamnet med genom-modellens `_meta.db_table`-egenskap. Din nya `through`-modell bör använda samma namn för `ForeignKey`s som Django gjorde. Om den behöver några extra fält bör dessa läggas till i operationer efter `SeparateDatabaseAndState`.

Om vi till exempel hade en `Book`-modell med ett `ManyToManyField` som länkar till `Author`, skulle vi kunna lägga till en genomgående modell `AuthorBook` med ett nytt fält `is_primary`, så här:

    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",
                                ),
                            ),
                        ],
                        options={
                            "constraints": [
                                models.UniqueConstraint(
                                    fields=["author", "book"],
                                    name="unique_author_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),
            ),
        ]

## Ändring av en ostyrd modell till styrd

Om du vill ändra en ohanterad modell (`managed=False`) till hanterad måste du ta bort `managed=False` och generera en migrering innan du gör andra schemarelaterade ändringar i modellen, eftersom schemaändringar som visas i den migrering som innehåller åtgärden för att ändra `Meta.managed` kanske inte tillämpas.