---
title: "How to create database migrations"
version: 4.0
locale: ko
source: https://docs.djangoproject.com/ko/4.0/howto/writing-migrations/
canonical: https://djangodocs.dev/ko/4.0/howto/writing-migrations/
---
# How to create database migrations

이 문서에서는 발생할 수 있는 다양한 시나리오에 대해 데이터베이스 마이그레이션을 구성하고 쓰는 방법을 설명합니다. 마이그레이션에 대한 소개 자료는 :doc: ‘주제 가이드’를 참조하십시오.

## 데이터 마이그레이션 및 여러 데이터베이스를 사용합니다.

여러 데이터베이스를 사용할 때 특정 데이터베이스에 대해 마이그레이션을 실행할지 여부를 결정해야 할 수도 있습니다. 예를 들어 특정 데이터베이스에서 만\* 마이그레이션을 실행할 수 있습니다.

그러기 위해서 당신은 schema\_editor.connection”을 보면 RunPython” 운영 내에서 데이터베이스 연결의 별칭을 확인할 수 있습니다.별칭 속성:입니다.

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

\<div\>\</div\>

*`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
```

마이그레이션 시 이 기능을 활용하려면 다음을 수행하십시오.

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

만일 당신의 RunPython” 또는 “RunSQL” 작업이 하나의 모델에만 영향을 준다면, 가능한 한 투명하게 라우터에 알리기 위해 “model\_name”을 힌트로 전달하는 것이 좋은 관행입니다. 이는 재사용 가능한 앱과 타사 앱에서 특히 중요합니다.

## 고유한 필드를 추가하는 마이그레이션입니다.

기존 행이 있는 테이블에 null이 아닌 고유한 필드를 추가하는 “일반” 마이그레이션을 적용하면 기존 행을 채우는 데 사용되는 값이 한 번만 생성되므로 고유한 제약 조건이 해제되기 때문에 오류가 발생합니다.

따라서 다음 단계를 수행해야 합니다. 이 예에서는 Null이 아닌 :class를 추가합니다.’~django.db.db.class입니다.기본값인 UUIDField’입니다. 필요에 따라 각 필드를 수정합니다.

- default = uuid”를 사용하여 모델에 필드를 추가합니다.uuid4와 “hydp\*”로 구성됩니다.True’ 인수(추가하려는 필드 유형에 적합한 기본값 선택)를 선택합니다.
- :djadmin:’make migration’ 명령을 실행합니다. 이는 Add Field” 작전으로 이주를 창출해야 합니다.
- 동일한 앱에 대해 “마이 앱으로 마이그레이션 – 비우기”를 두 번 실행하여 두 개의 빈 마이그레이션 파일을 생성합니다. 아래의 예에서 의미 있는 이름을 지정하기 위해 마이그레이션 파일의 이름을 변경했습니다.
- “AddField” 작업을 자동 생성 마이그레이션(새 파일 3개 중 첫 번째 파일)에서 마지막 마이그레이션으로 복사하고 “AddField”를 “AlterField”로 변경하고 “uuid” 및 “model” 수입을 추가합니다. 예를 들어 다음과 같습니다.

  *`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),
          ),
      ]
  ```
- 첫 번째 마이그레이션 파일을 편집합니다. 생성된 마이그레이션 클래스는 다음과 유사하게 표시되어야 합니다.

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

  ‘’변신’’을 하세요.True’ to “null ull True” – 이렇게 하면 중간 null 필드가 생성되고 모든 행에 고유 값을 채울 때까지 고유한 제약 조건 생성이 지연됩니다.
- 첫 번째 빈 마이그레이션 파일에서 :class를 추가하십시오.’~django.db.migrations.operations입니다.Python’ 또는 :class를 실행합니다.’~django.db.migrations.operations입니다.SQL 작업을 실행하여 각 기존 행에 대해 고유한 값(예제의 UUID)을 생성합니다. 또한 “uuid”의 가져오기를 추가합니다. 예를 들어 다음과 같습니다.

  *`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),
      ]
  ```
- 이제 :djadmin:’migrate’ 명령을 사용하여 평소와 같이 마이그레이션을 적용할 수 있습니다.

  마이그레이션이 실행되는 동안 개체를 만들 수 있는 경우 경합 조건이 있습니다. “AddField” 이후와 “Run Python” 이전에 만들어진 물체들은 원래의 “uuid”를 덮어쓸 것입니다.

### 비원자성 마이그레이션입니다.

DDL 트랜잭션을 지원하는 데이터베이스(SQLite 및 Postgre)입니다.SQL) 마이그레이션은 기본적으로 트랜잭션 내에서 실행됩니다. 대형 테이블에서 데이터 마이그레이션을 수행하는 경우와 같은 사용 사례의 경우 “원자” 속성을 “거짓”으로 설정하여 트랜잭션에서 마이그레이션이 실행되지 않도록 할 수 있습니다.

```
from django.db import migrations

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

이러한 마이그레이션 내에서 모든 작업은 트랜잭션 없이 실행됩니다. func:’~django.db.transaction.transaction.transaction.transaction’을 사용하거나 “transaction”을 전달하여 트랜잭션 내 마이그레이션의 일부를 실행할 수 있습니다.”피톤을 운영하라”는 말은 사실입니다.

다음은 더 작은 배치로 큰 테이블을 업데이트하는 비원자 데이터 마이그레이션의 예입니다.

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

“원자” 특성은 DDL 트랜잭션을 지원하지 않는 데이터베이스(예: MySQL, Oracle)에는 영향을 미치지 않습니다. (MySQL의 ‘dsl statement support <https://dev.mysql.com/doc/refman/en/atomic-ddl.html>’\_은(는) 롤백할 수 있는 트랜잭션에 포함된 여러 개의 문이 아닌 개별 문을 말합니다.)

## 마이그레이션 순서 제어

Django는 각 마이그레이션의 파일 이름이 아니라 “이민” 클래스의 dependency”와 “run\_before”라는 두 가지 속성을 사용하여 마이그레이션이 적용되어야 하는 순서를 결정합니다.

“djadmin:”make migration” 명령을 사용했다면 자동 생성된 마이그레이션은 생성 과정의 일부로 정의되기 때문에 “dependency”가 이미 실행 중인 것을 보았을 것입니다.

“의존성” 재산은 다음과 같이 선언됩니다.

```
from django.db import migrations

class Migration(migrations.Migration):

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

일반적으로 이 정도면 충분하지만 때때로 마이그레이션이 *다른 마이그레이션 전에* 실행되도록 해야 할 수도 있습니다. 예를 들어, 이 기능은 타사 앱의 마이그레이션을 *다음* 이후에 실행하도록 하는 데 유용합니다. 설정:’AUTH\_USER\_MODEL을 대체합니다.

이를 위해 귀사에 의존해야 할 모든 마이그레이션을 귀국의 이민” 등급의 실행 전” 속성으로 배치하십시오.

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

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

가능하면 실행 전”보다 “의존적”을 사용하는 것을 선호합니다. 작성 중인 마이그레이션 이후에 실행할 마이그레이션에 의존성”을 지정하는 것이 바람직하지 않거나 비실용적인 경우에만 “run\_before”를 사용해야 합니다.

## 타사 앱 간에 데이터를 마이그레이션하고 있습니다.

데이터 마이그레이션을 사용하여 한 타사 응용 프로그램에서 다른 응용 프로그램으로 데이터를 이동할 수 있습니다.

나중에 기존 앱을 제거할 계획이라면 기존 앱의 설치 여부에 따라 “의존성” 속성을 설정해야 합니다. 그렇지 않으면 이전 앱을 제거한 후 종속성이 누락됩니다. 마찬가지로 exc를 확인해야 합니다.기존 앱에서 모델을 검색하는 apps.get\_model()” 통화에서 “Lookup Error”가 발생합니다. 이 방법을 사용하면 먼저 이전 앱을 설치한 다음 제거하지 않고도 프로젝트를 아무 곳에나 배포할 수 있습니다.

다음은 마이그레이션 예 입니다:

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

또한 마이그레이션이 적용되지 않을 때 수행할 작업도 고려하십시오. 위의 예와 같이 아무 작업도 수행하지 않거나 새 응용 프로그램에서 일부 또는 모든 데이터를 제거할 수 있습니다. :mod의 두 번째 인수를 조정합니다.’~django.db.migrations.operations입니다.이에 따라 파이썬을 실행합니다.

## `ManyToManyField` 를 바꾸어 `through`  모델을 사용합니다.

If you change a [`ManyToManyField`](/ko/4.0/ref/models/fields/#django.db.models.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`](/ko/4.0/ref/migration-operations/#django.db.migrations.operations.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`](/ko/4.0/ref/django-admin/#django-admin-sqlmigrate) or [`dbshell`](/ko/4.0/ref/django-admin/#django-admin-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`](/ko/4.0/ref/migration-operations/#django.db.migrations.operations.SeparateDatabaseAndState).

예를 들어 우리가 다수로”를 저자”로 연결한 책” 모델을 가지고 있다면 다음과 같이 새로운 분야의 “is\_primary”를 가진 저자책”을 추가할 수 있을 것입니다.

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

## 관리되지 않는 모델을 관리 대상으로 변경합니다.

관리되지 않는 모델(:attr:’managed \>False \<django.db.db.closed)을 변경하려는 경우입니다.관리 대상인 Options.managed\>’에서는 “Meta.managed” 변경 작업을 포함하는 마이그레이션에 표시되는 스키마 변경 사항이 적용되지 않을 수 있으므로 모델을 변경하기 전에 “Managed =”을 제거하고 마이그레이션을 생성해야 합니다.
