# documentação Django 4.0.8.dev20220803071047

# How to create database migrations

Este documento explica como estruturar e a escrever migrações de banco de dados para diferentes cenários que você talvez encontre. Para um material introdutório sobre migrações, veja o tópico guia.

## Migrações de dados e múltiplos bancos de dados

Quando usar múltiplos bancos de dados, você talvez necessite entender onde rodar e onde não rodar migrações para um banco de dados em partiular. Por exemplo, você talvez queira somente rodar migrações em um banco de dados particular.

Para fazer isso você pode verificar o alias da conexão com o banco de dados dentro de uma operação `RunPython` olhando no 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),
        ]

Você pode fornecer dicas que serão passadas para o método `allow_migrate()` do roteador de banco de dados como `**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

Então para aproveitar isso em suas migrações, faça o seguinte:

    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 você executar `RunPython` ou `RunSQL` as operações só irão afetar um modelo, e é uma boa prática passar `model_name` como uma dica para que fique tão transparente quanto possível para o roteador. Isso é especialmente importante para reutilização e aplicações de terceiros.

## Migrações que adicionam campos “unique”

Aplicar uma migração “sem customizações” que adicione um campo não nulo e “unique” a uma table com registros existentes irá emitir um erro porque o valor usado para popular os registros existente é gerado somente uma vez, então quebrando a regra de “unique”.

Portanto, os seguintes passos devem ser seguidos. Neste exemplo, nós iremos adicionar um `UUIDField` não-nulo com um valor padrão. Modifique o campo respectivo de acordo com suas necessidades.

- Adicione o campo no seu modelo com `default=uuid.uuid4` e argumentos `unique=True` (escolha um padrão apropriado para o tipo de campor que você está adicionando).

- Execute o comando `makemigrations` . Isso deve gerar uma migração com uma operação `AddField`.

- Gera dois arquivos de migrações vazios para a mesma aplicação rodando `makemigrations myapp --empty` duas vezes. Renomeamos os arquivos de migração para dara eles nomes significativos nos exemplos abaixo

- Copie a operação `AddField` da migração gerada automatcamente (a primeira dos três arquivos novos) para a última migração, troque `AddField` para `AlterField`, e adicione as importações de `uuid` e `models``. Por exemplo:

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

- Edite o primeiro arquivo da migração. A classe de migração gerada deve se parecer com isso:

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

  Mude `unique=True` para `null=True` – isso irá criar o campo nullo imtermediário e adiar a criação da restrição “unique” até que tenhamos populado os valores únicos em todas os registros.

- No primeiro arquivo de migração vazio, adicione a operação `RunPython` ou a `RunSQL` para gerar um valor único (UUID por exemplo) para cada linha existente. Também adicione uma importação de `uuid`. Por exemplo:

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

- Agora você pode aplicar as migrações como de costume com o comando `migrate`.

  Note que há uma condição de concorrência se você deixar com que objetos sejam criados enquanto essa migração está rodando. Objetos criados depois do `AddField``e antes do ``RunPython` terão seus `uuid`’s sobrescritos.

### Migrações não atômicas

Em banco de dados que suportam transações DDL (SQLite e PostgreSQL), as migrações são executadas por padrão dentro de uma transação. Em casos como migrações de dados em grandes tabelas, você talvez queira evitar que uma migração rode em uma transação definindo o atributo `atomic` como `False`:

    from django.db import migrations

    class Migration(migrations.Migration):
        atomic = False

Dentro de uma migração como esta, todas as operações rodam sem uma transação. É possível executar partes da migração dentro de uma transação usando `atomic()` ou passando `atomic=True` para `RunPython`.

Aqui um exemplo de uma migração de dados não atômica que atualiza uma grande tabela em pequenas partes.

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

O atributo `atomic` não tem nenhum efeito em bancos de dados que não suportam transações DDL (ex. MySQL, Oracle). (O suporte para transações DDL atômicas do MySQL refere-se a instruções individuais, em vez de várias instruções envolvidas em uma transação que pode ser revertida.)

## Controlando a ordem das migrações

O django determina a ordem em que as migrações devem ser aplicadas não pelo nome do arquivo de cada migração, mas através da construção de um gráfico usando duas propriedade na classe `Migration`: `dependencies` e `run_before`.

Se você estiver usando o comando `makemigration` você provavelmente já viu `dependencies` em ação por conta das migrações auto-criadas possuirem esta definição como parte do processo de criação.

A propridade `dependencies` está declarada como isto:

    from django.db import migrations

    class Migration(migrations.Migration):

        dependencies = [
            ('myapp', '0123_the_previous_migration'),
        ]

Normalmente isso será o bastante, mas de tempos em tempos você poderá precisar se assegurar de que sua migração execute antes de outras migrações. Isso é útil, por exemplo, para fazer migrações de aplicações de terceiros executem depois de substituir seu `AUTH_USER_MODEL`.

Para conseguir isso, coloque todas as migrações que devem depender das suas no atributo `run_before` na sua classe `Migration`:

    class Migration(migrations.Migration):
        ...

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

Prefira usar `dependencies` ao `run_before` quando possível. Você deve somente usar o `run_before` se não é desejável ou impraticável especificar `dependencies` na migração qual você quer rodar depois da que está escrevendo.

## Migrando dados entre aplicativos de terceiros

Pode-se usar migração de dados para mover dados de um aplicativo de terceiros até outro aplicativo.

Se você planeja remover o aplicativo antigo depois, você vai precisar definir propriedades de `dependencies` baseadas em se o aplicativo está ou não instalado. Caso contrário, você terá dependências faltando uma vez que o aplicativo antigo seja desinstalado. De forma similar, você precisa prestar atenção no `LookupError` na função `apps.get_model()` que retorna modelos do aplicativo antigo. Esta abordagem lhe permite implementar o seu projeto em qualquer lugar sem precisar instalar primeiro e depois desinstalar o aplicativo antigo.

Este é um exemplo de migração:

`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'))

Considere também o que você quer que aconteça quando uma migração não for aplicada. Você pode não fazer nada (como no exemplo acima) ou remover alguns ou todos os dados da nova aplicação. Ajuste o segundo argumento da operação `RunPython` de acordo.

## Changing a `ManyToManyField` to use a `through` model

If you change a `ManyToManyField` to use a `through` model, the default migration will delete the existing table and create a new one, losing the existing relations. To avoid this, you can use `SeparateDatabaseAndState` to rename the existing table to the new table name while telling the migration autodetector that the new model has been created. You can check the existing table name through `sqlmigrate` or `dbshell`. You can check the new table name with the through model’s `_meta.db_table` property. Your new `through` model should use the same names for the `ForeignKey`s as Django did. Also if it needs any extra fields, they should be added in operations after `SeparateDatabaseAndState`.

For example, if we had a `Book` model with a `ManyToManyField` linking to `Author`, we could add a through model `AuthorBook` with a new field `is_primary`, like so:

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

## Mudando um modelo não gerenciável para gerenciável

Se quiser alterar um modelo não gerenciado (`managed=False`) para gerenciado, você deve remover `managed=False` e gerar uma migração antes de fazer outras mudanças no modelo relacionadas ao esquema, uma vez que alterações que aparecem na migração que contém a operação para alterar o `Meta.managed` podem não ser aplicadas.