Django-DB-Migrations: ไม่สามารถแก้ไขตารางได้เนื่องจากมีเหตุการณ์ทริกเกอร์ที่รอดำเนินการ


122

ฉันต้องการลบ null = True จาก TextField:

-    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 shell) เข้าไปและอัปเดตค่าที่ไม่เป็นไปตามข้อกำหนด
mgojohn

@mgojohn คุณทำได้อย่างไร?
pyramidface

1
@pyramidface ถ้าคุณไม่จู้จี้จุกจิกเกินไปคุณสามารถอัปเดตค่า null ได้ที่ django shell หากคุณกำลังมองหาสิ่งที่เป็นทางการและทดสอบได้ขึ้นอยู่กับเวอร์ชันที่คุณใช้ หากคุณใช้ทิศใต้โปรดดู: south.readthedocs.org/th/latest/tutorial/part3.htmlและหากคุณใช้การย้ายข้อมูลของ django โปรดดูส่วน "การย้ายข้อมูล" ที่นี่: docs.djangoproject.com/en/1.8/topics/ การโยกย้าย
mgojohn

131

ทุกการย้ายข้อมูลอยู่ในธุรกรรม ใน PostgreSQL คุณจะต้องไม่อัปเดตตารางและจากนั้นแก้ไข schema ของตารางในธุรกรรมเดียว

คุณต้องแยกการย้ายข้อมูลและการย้ายสคีมา ขั้นแรกให้สร้างการย้ายข้อมูลด้วยรหัสนี้:

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

จากนั้นสร้างการย้ายสคีมา:

manage.py schemamigration fooapp --auto

ตอนนี้คุณมีธุรกรรมสองรายการและการโยกย้ายในสองขั้นตอนควรใช้งานได้


8
PostgreSQL อาจเปลี่ยนพฤติกรรมเกี่ยวกับธุรกรรมดังกล่าวเนื่องจากฉันสามารถเรียกใช้การย้ายข้อมูลด้วยการเปลี่ยนแปลงทั้งข้อมูลและสคีมาบนเครื่อง dev ของฉัน (PostgreSQL 9.4) ในขณะที่ล้มเหลวบนเซิร์ฟเวอร์ (PostgreSQL 9.1)
Bertrand Bordage

1
เกือบจะเหมือนกันสำหรับฉัน ทำงานได้อย่างไม่มีที่ติสำหรับการย้ายข้อมูลมากกว่า 100 รายการ (รวมถึงการย้ายข้อมูล ~ 20 รายการ) จนถึงวันนี้ในขณะที่เพิ่มข้อ จำกัด ที่ไม่ซ้ำกันพร้อมกับการย้ายข้อมูลเพื่อลบรายการที่ซ้ำกันก่อนหน้านั้น PostgreSQL 10.0
LinPy fan

หากใช้การดำเนินการ RunPython ในการโอนย้ายข้อมูลคุณเพียงแค่ต้องตรวจสอบให้แน่ใจว่าเป็นการดำเนินการสุดท้าย Django รู้ว่าหากการดำเนินการ RunPython เป็นครั้งสุดท้ายเพื่อเปิดธุรกรรมของตัวเอง
Dougyfresh

1
@Dougyfresh นี่เป็นคุณสมบัติที่บันทึกไว้ของ django หรือไม่?
guettli

ที่จริงฉันไม่เห็นสิ่งนี้เลยเป็นเพียงสิ่งที่ฉันสังเกตเห็น docs.djangoproject.com/th/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: ไม่สามารถแก้ไขตาราง "mytable" ได้เนื่องจากมีเหตุการณ์ทริกเกอร์ที่รอดำเนินการอยู่
Iasmini Gomes


1

คุณกำลังแก้ไขสคีมาของคอลัมน์ คอลัมน์ส่วนท้ายนั้นจะไม่มีค่าว่างอีกต่อไป มีค่าว่างที่เป็นไปได้มากที่สุดที่เก็บไว้ในฐานข้อมูลสำหรับคอลัมน์นั้น Django กำลังจะอัปเดตแถวว่างเหล่านั้นในฐานข้อมูลของคุณจากค่าว่างเป็นค่าเริ่มต้นในขณะนี้ด้วยคำสั่งโยกย้าย Django พยายามอัปเดตแถวที่คอลัมน์ส่วนท้ายมีค่าว่างและเปลี่ยนสคีมาในเวลาเดียวกัน (ฉันไม่แน่ใจ)

ปัญหาคือคุณไม่สามารถแก้ไขสคีมาคอลัมน์เดียวกันกับที่คุณพยายามอัปเดตค่าในเวลาเดียวกันได้

ทางออกหนึ่งคือการลบไฟล์การย้ายข้อมูลที่อัปเดตสคีมา จากนั้นเรียกใช้สคริปต์เพื่ออัปเดตค่าเหล่านั้นทั้งหมดเป็นค่าเริ่มต้นของคุณ จากนั้นเรียกใช้การย้ายข้อมูลอีกครั้งเพื่ออัปเดตสคีมา วิธีนี้การอัปเดตเสร็จสิ้นแล้ว การโยกย้าย Django เป็นเพียงการแก้ไขสคีมาเท่านั้น


1
การเรียกใช้สคริปต์บางส่วนไม่ใช่ตัวเลือกสำหรับฉัน ฉันมีหลายอินสแตนซ์ของฐานข้อมูลและกระบวนการปรับใช้อย่างต่อเนื่องเพียงแค่เรียก "Manage.py migrate" คำถามนี้เป็นคำตอบที่ใช้ได้ผลดีอยู่แล้ว
guettli
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.