이 문서에서는 발생할 수 있는 다양한 시나리오에 대해 데이터베이스 마이그레이션을 구성하고 쓰는 방법을 설명합니다. 마이그레이션에 대한 소개 자료는 :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>
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》 수입을 추가합니다. 예를 들어 다음과 같습니다.
# 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),
),
]
첫 번째 마이그레이션 파일을 편집합니다. 생성된 마이그레이션 클래스는 다음과 유사하게 표시되어야 합니다.
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》의 가져오기를 추가합니다. 예를 들어 다음과 같습니다.
# 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》가 발생합니다. 이 방법을 사용하면 먼저 이전 앱을 설치한 다음 제거하지 않고도 프로젝트를 아무 곳에나 배포할 수 있습니다.
다음은 마이그레이션 예 입니다:
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
모델을 사용합니다.¶:class를 변경할 경우 다음을 수행합니다.〉~django.db.db.class입니다.많은 ToMoneyField가 ``통과》 모델을 사용하기 위해 디폴트 마이그레이션은 기존 테이블을 삭제하고 새로운 테이블을 만들어 기존 관계를 잃게 될 것입니다. 이 문제를 방지하려면:class:mc를 사용할 수 있습니다.〉SeparateDatabaseAndState’를 선택하면 마이그레이션 자동 검색기에 새 모델이 생성되었음을 알려 주면서 기존 테이블 이름을 새 테이블 이름으로 바꿀 수 있습니다. :djadmin:〉sqlmigrate〉 또는 :djadmin:〉dbshell’을 통해 기존 테이블 이름을 확인할 수 있습니다. 새 테이블 이름은 through 모델의 《_meta.db_table》 속성으로 확인할 수 있습니다. 당신의 새 ``스루》 모델은 장고와 같은 《외국인 키》의 이름을 사용해야 합니다. 또한 추가 필드가 필요한 경우:class:class:mcret 이후 작업에 추가해야 합니다.데이터베이스와 상태를 구분하십시오.
예를 들어 우리가 ``다수로》를 ``저자》로 연결한 ``책》 모델을 가지고 있다면 다음과 같이 새로운 분야의 《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 =》을 제거하고 마이그레이션을 생성해야 합니다.
4월 06, 2021