Django-DB-Migrations : 보류중인 트리거 이벤트가 있으므로 ALTER TABLE을 사용할 수 없습니다.


122

TextField에서 null = True를 제거하고 싶습니다.

-    footer=models.TextField(null=True, blank=True)
+    footer=models.TextField(blank=True, default='')

스키마 마이그레이션을 생성했습니다.

manage.py schemamigration fooapp --auto

일부 바닥 글 열에 는 마이그레이션을 실행하면 NULL다음이 포함 error됩니다.

django.db.utils.IntegrityError : "footer"열에 null 값이 있습니다.

나는 이것을 스키마 마이그레이션에 추가했습니다.

    for sender in orm['fooapp.EmailSender'].objects.filter(footer=None):
        sender.footer=''
        sender.save()

이제 다음을 얻습니다.

django.db.utils.DatabaseError: cannot ALTER TABLE "fooapp_emailsender" because it has pending trigger events

뭐가 잘못 되었 니?


1
이 질문은 비슷합니다. stackoverflow.com/questions/28429933/… 그리고 나에게 더 유용한 답변이있었습니다.
SpoonMeiser

답변:


139

이에 대한 또 다른 이유는 열에 NOT NULL실제로 이미 NULL값 이있을 때 열을 설정하려고하기 때문일 수 있습니다.


7
이 문제를 해결하기 위해 당신도 업데이트 호환되지 않는 값에 가서 수동으로 데이터 마이그레이션 또는 (manage.py 쉘)를 사용할 수 있습니다
mgojohn

@mgojohn 어떻게하나요?
pyramidface

1
@pyramidface 너무 까다 롭지 않다면 django 셸에서 null 값을 업데이트 할 수 있습니다. 보다 공식적이고 테스트 가능한 것을 찾고 있다면 사용중인 버전에 따라 다릅니다. south를 사용하는 경우 south.readthedocs.org/en/latest/tutorial/part3.html을 참조하고 django의 마이그레이션을 사용하는 경우 여기에서 "데이터 마이그레이션"섹션을 참조하십시오. docs.djangoproject.com/en/1.8/topics/ 마이그레이션
mgojohn 2015-07-29

131

모든 마이그레이션은 트랜잭션 내부에 있습니다. PostgreSQL에서는 테이블을 업데이트 한 다음 하나의 트랜잭션에서 테이블 스키마를 변경해서는 안됩니다.

데이터 마이그레이션과 스키마 마이그레이션을 분할해야합니다. 먼저 다음 코드를 사용하여 데이터 마이그레이션을 만듭니다.

 for sender in orm['fooapp.EmailSender'].objects.filter(footer=None):
    sender.footer=''
    sender.save()

그런 다음 스키마 마이그레이션을 만듭니다.

manage.py schemamigration fooapp --auto

이제 두 개의 트랜잭션이 있으며 두 단계의 마이그레이션이 작동합니다.


8
PostgreSQL은 서버 (PostgreSQL 9.1)에서 실패한 동안 내 dev 컴퓨터 (PostgreSQL 9.4)에서 데이터 및 스키마 변경 사항을 모두 사용하여 마이그레이션을 실행할 수 있었기 때문에 이러한 트랜잭션에 대한 동작을 변경했을 것입니다.
Bertrand Bordage 2015 년

1
저도 거의 같습니다. 현재까지 100 개 이상의 마이그레이션 (~ 20 개 데이터 마이그레이션 포함)에서 완벽하게 작동했으며, 데이터 마이그레이션과 함께 고유 한 제약 조건을 추가하여 이전에 중복 된 항목을 제거했습니다. PostgreSQL 10.0
LinPy 팬

데이터 마이그레이션을위한 마이그레이션에서 RunPython 작업을 사용하는 경우 마지막 작업인지 확인하기 만하면됩니다. Django는 RunPython 작업이 마지막이면 자체 트랜잭션을 여는 것을 알고 있습니다.
Dougyfresh

1
@Dougyfresh가 장고의 문서화 된 기능입니까?
guettli

나는 실제로 이것을 어디에도 보지 못하고 단지 내가 관찰 한 것이었다. docs.djangoproject.com/en/2.2/ref/migration-operations/…
Dougyfresh

9

이 문제가 발생했습니다. 스키마 마이그레이션에서 db.start_transaction () 및 db.commit_transaction ()을 사용하여 데이터 변경 사항과 스키마 변경 사항을 구분할 수도 있습니다. 아마도 별도의 데이터 마이그레이션이있을만큼 깨끗하지는 않지만 제 경우에는 스키마, 데이터 및 다른 스키마 마이그레이션이 필요하므로 한 번에 모두 수행하기로 결정했습니다.


7
이 솔루션의 문제점은 다음과 같습니다. db.commit_transaction () 후 마이그레이션이 실패하면 어떻게됩니까? 필요한 경우 schema-mig, data-mig, schema-mig의 세 가지 마이그레이션을 사용하는 것이 좋습니다.
guettli

5
참조 : django.readthedocs.io/en/latest/ref/migration-operations.html DDL 트랜잭션 (SQLite 및 PostgreSQL)을 지원하는 데이터베이스에서 RunPython 작업에는 각 마이그레이션에 대해 생성 된 트랜잭션 외에 자동으로 추가되는 트랜잭션이 없습니다. 따라서 예를 들어 PostgreSQL에서는 동일한 마이그레이션에서 스키마 변경과 RunPython 작업을 결합하지 않아야합니다. 그렇지 않으면 보류중인 트리거 이벤트가 있기 때문에 OperationalError : cannot ALTER TABLE "mytable"과 같은 오류가 발생할 수 있습니다.
Iasmini Gomes

5

작업에서 SET CONSTRAINTS를 넣습니다.

operations = [
    migrations.RunSQL('SET CONSTRAINTS ALL IMMEDIATE;'),
    migrations.RunPython(migration_func),
    migrations.RunSQL('SET CONSTRAINTS ALL DEFERRED;'),
]


0

열 스키마를 변경하고 있습니다. 해당 바닥 글 열은 더 이상 빈 값을 포함 할 수 없습니다. 해당 열에 대해 DB에 이미 저장된 빈 값이있을 가능성이 높습니다. Django는 migrate 명령을 사용하여 DB의 빈 행을 공백에서 현재 기본값으로 업데이트합니다. Django는 바닥 글 열에 빈 값이있는 행을 업데이트하고 보이는 것과 동시에 스키마를 변경하려고 시도합니다 (확실하지 않습니다).

문제는 동시에 값을 업데이트하려는 동일한 열 스키마를 변경할 수 없다는 것입니다.

한 가지 해결책은 스키마를 업데이트하는 마이그레이션 파일을 삭제하는 것입니다. 그런 다음 스크립트를 실행하여 모든 값을 기본값으로 업데이트하십시오. 그런 다음 마이그레이션을 다시 실행하여 스키마를 업데이트하십시오. 이렇게하면 업데이트가 이미 완료되었습니다. Django 마이그레이션은 스키마 만 변경합니다.


1
일부 스크립트를 실행하는 것은 나에게 실제로 옵션이 아닙니다. 데이터베이스의 여러 인스턴스가 있고 지속적인 배포 프로세스는 "manage.py 마이그레이션"이라고합니다. 이 질문은 이미 잘 작동하는 유효한 답변입니다.
guettli
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.