IT

Django-DB-Migrations: 보류 중인 트리거 이벤트가 있기 때문에 TABLE을 변경할 수 없습니다.

itgroup 2023. 5. 18. 20:58
반응형

Django-DB-Migrations: 보류 중인 트리거 이벤트가 있기 때문에 TABLE을 변경할 수 없습니다.

텍스트 필드에서 null=True를 제거합니다.

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

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

manage.py schemamigration fooapp --auto

일부 바닥글 열에 다음이 포함되어 있기 때문에NULL알겠습니다error마이그레이션을 실행하는 경우:

django.db.dll 파일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

뭐가 문제야?

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

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

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

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

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

manage.py schemamigration fooapp --auto

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

작업 시 SET 제약 조건:

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

null이 아닌 필드를 추가하는 경우 다음 두 가지 마이그레이션을 수행해야 합니다.

  1. AddField그리고.RunPython그것을 채우기 위해
  2. AlterField필드를 취소할 수 없도록 변경합니다.

설명.

포스트그레에서SQL 및 SQLite, 이 문제는 충분히 복잡한 경우에 발생할 수 있습니다.RunPython동일한 마이그레이션에서 스키마 변경사항과 결합된 명령입니다.예를 들어 null이 아닌 필드를 추가하는 경우 일반적인 마이그레이션 단계는 다음과 같습니다.

  1. AddField필드를 null로 추가합니다.
  2. RunRython그것을 채우기 위해
  3. AlterField필드를 취소할 수 없도록 변경합니다.

SQLite 및 Postgres에서는 전체 작업이 한 번의 트랜잭션으로 수행되므로 문제가 발생할 수 있습니다.
Django 문서에는 다음과 같은 특정 경고가 있습니다.

DDL 트랜잭션(SQLite 및 Postgre)을 지원하는 데이터베이스SQL), RunPython 작업에는 각 마이그레이션에 대해 생성된 트랜잭션 외에 어떤 트랜잭션도 자동으로 추가되지 않습니다.따라서, Postgre에서.예를 들어 SQL은 동일한 마이그레이션에서 스키마 변경 사항과 RunPython 작업을 결합하지 않도록 해야 합니다. 그렇지 않으면 보류 중인 트리거 이벤트가 있기 때문에 OperationalError: cannot ALTER TABLE "mytable"과 같은 오류가 발생할 수 있습니다.

이 경우 마이그레이션을 여러 마이그레이션으로 분리하는 것이 해결책입니다.일반적으로 분할하는 방법은 run_python 명령을 통해 단계가 올라가는 첫 번째 마이그레이션과 그 이후의 모든 마이그레이션을 포함하는 두 번째 마이그레이션을 갖는 것입니다.따라서, 위에서 설명한 경우, 패턴은AddField그리고.RunPython한 번의 마이그레이션에서, 그리고AlterField순식간에.

방금 이 문제를 해결했습니다.스키마 마이그레이션에서 db.start_transaction() 및 db.commit_transaction()을 사용하여 데이터 변경과 스키마 변경을 구분할 수도 있습니다.별도의 데이터 마이그레이션을 수행할 정도로 깨끗하지는 않지만, 저의 경우 스키마, 데이터, 그리고 또 다른 스키마 마이그레이션이 필요하기 때문에 한 번에 모두 수행하기로 결정했습니다.

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

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

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

저 같은 경우에는

  1. 필드 추가
  2. 런 파이썬
  3. 필드 제거

그런 다음 마지막 RemoveFied를 새 마이그레이션 파일로 이동하여 문제를 해결했습니다.

1단계) 솔루션은 마이그레이션 폴더에서 최신 마이그레이션을 제거하고 모델에서 추가된 최신 필드를 제거하는 것입니다.

2단계) 다시 마이그레이션 및 마이그레이션

3단계) 마지막에 첫 번째 단계에서 제거된 필드를 다시 추가합니다.

4단계) 다시 마이그레이션 및 마이그레이션

문제는 해결됐습니다.

언급URL : https://stackoverflow.com/questions/12838111/django-db-migrations-cannot-alter-table-because-it-has-pending-trigger-events

반응형