Django-DB-Migrations: TTER ALABLE नहीं कर सकता क्योंकि इसमें ट्रिगर इवेंट लंबित हैं


121

मैं एक 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: कॉलम "पाद" में शून्य मान हैं

मैंने इसे स्कीमा माइग्रेशन में जोड़ा:

    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/… और मेरे पास ऐसे उत्तर थे जो मेरे लिए अधिक उपयोगी थे।
स्पूनमाइज़र

जवाबों:


138

इसका एक और कारण शायद हो सकता है क्योंकि आप एक कॉलम को सेट करने की कोशिश करते हैं NOT NULLजब यह वास्तव में पहले से ही NULLमूल्य है।


7
इसे संबोधित करने के लिए आप या तो एक डेटा माइग्रेशन या मैन्युअल रूप से (manage.py शेल) का उपयोग कर सकते हैं और गैर-संगत मानों को अपडेट कर सकते हैं
mgojohn

@mgojohn आप ऐसा कैसे करते हैं?
पिरामिड

1
@ पिरामिड पिरामिड यदि आप बहुत अधिक योग्य नहीं हैं, तो आप बस django शेल में शून्य मानों को अपडेट कर सकते हैं। यदि आप कुछ अधिक औपचारिक और परीक्षण योग्य हैं, तो यह इस बात पर निर्भर करता है कि आप किन संस्करणों का उपयोग कर रहे हैं। यदि आप दक्षिण का उपयोग करते हैं, तो देखें: south.readthedocs.org/en/latest/tutorial/part3.html और यदि आप django के माइग्रेशन का उपयोग करते हैं, तो यहां "डेटा माइग्रेशन" अनुभाग देखें: docs.djangopodject.com/en/1.8/topics/ माइग्रेशन
mgojohn

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.4) जब यह सर्वर पर विफल हो गया (PostgreSQL 9.1)।
बर्ट्रेंड बोर्डेज

1
मेरे लिए लगभग वही। यह आज तक 100+ माइग्रेशन (~ 20 डेटा माइग्रेशन सहित) के लिए त्रुटिपूर्ण रूप से काम करता है, जबकि इससे पहले डुप्लिकेट को हटाने वाले डेटा माइग्रेशन के साथ-साथ अद्वितीय को एक साथ जोड़ रहा है। PostgreSQL 10.0
लिनपी फैन

यदि डेटा माइग्रेशन के लिए माइग्रेशन में RunPython ऑपरेशन का उपयोग किया जाता है, तो आपको यह सुनिश्चित करने की आवश्यकता है कि यह अंतिम ऑपरेशन है। Django जानता है कि यदि RunPython ऑपरेशन अंतिम है, तो अपना लेनदेन खोलने के लिए।
डॉग्फ्रेशेश

1
@Dougyfresh यह django की एक प्रलेखित विशेषता है?
गुफ्तगू

मैं वास्तव में इसे कहीं नहीं देखता, बस कुछ ऐसा था जिसे मैंने देखा था। docs.djangoproject.com/en/2.2/ref/migration-operations/…
Dougyfresh

9

बस इस समस्या को मारा है। स्कीमा परिवर्तन से डेटा परिवर्तनों को अलग करने के लिए आप स्कीमा माइग्रेशन में db.start_transaction () और db.commit_transaction () का उपयोग कर सकते हैं। संभवतः एक अलग डेटा माइग्रेशन करने के लिए इतना साफ नहीं है, लेकिन मेरे मामले में मुझे स्कीमा, डेटा और फिर एक और स्कीमा माइग्रेशन की आवश्यकता होगी, इसलिए मैंने एक ही बार में यह करने का फैसला किया।


7
इस समाधान के साथ समस्या यह है: यदि आपका माइग्रेशन db.commit_transaction () के बाद विफल हो जाता है तो क्या होगा? मुझे तीन माइग्रेशन का उपयोग करने का पूर्वाभास है, यदि आपको इसकी आवश्यकता है: स्कीमा-माइग, डेटा-माइग, स्कीमा-माइग।
गुफ्तगू

5
देखें: django.readthedocs.io/en/latest/ref/migration-operations.html डेटाबेस पर जो DDL लेन-देन (SQLite और PostgreSQL) का समर्थन करते हैं, RunPython के संचालन में कोई लेनदेन नहीं जोड़ा गया है इसके अलावा प्रत्येक माइग्रेशन के लिए किए गए लेनदेन को भी जोड़ा गया है। इस प्रकार, PostgreSQL पर, उदाहरण के लिए, आपको एक ही माइग्रेशन में स्कीमा परिवर्तन और RunPython संचालन के संयोजन से बचना चाहिए या आप ऑपरेशनलएयर की तरह त्रुटियों को मार सकते हैं: TABLE "mytable" नहीं कर सकते क्योंकि इसमें ट्रिगर इवेंट लंबित हैं।
Iasmini

5

संचालन में मैंने सेट कास्ट डाल दिया:

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

बेहतर उपयोग करने के लिए SeparateDatabaseAndState
bdoubleu

0

आप स्तंभ स्कीमा में परिवर्तन कर रहे हैं। उस पाद लेख स्तंभ में अब कोई रिक्त मान नहीं हो सकता है। उस कॉलम के लिए DB में पहले से संग्रहीत खाली मानों की सबसे अधिक संभावना है। Django माइग्रेट कमांड के साथ रिक्त स्थान से आपके DB में उन रिक्त पंक्तियों को रिक्त करने के लिए अद्यतन करने जा रहा है। Django उन पंक्तियों को अपडेट करने की कोशिश करता है जहां पाद लेख का एक रिक्त मान होता है और स्कीमा को उसी समय बदल देता है जब यह लगता है (मुझे यकीन नहीं है)।

समस्या यह है कि आप उसी कॉलम स्कीमा को बदल नहीं सकते हैं जिसे आप उसी समय के लिए मानों को अपडेट करने का प्रयास कर रहे हैं।

एक समाधान स्कीमा को अद्यतन करने वाली माइग्रेशन फ़ाइल को हटाने का होगा। फिर, उन सभी मानों को अपने डिफ़ॉल्ट मान को अद्यतन करने के लिए एक स्क्रिप्ट चलाएँ। फिर स्कीमा को अपडेट करने के लिए माइग्रेशन को फिर से चलाएं। इस तरह, अद्यतन पहले से ही किया गया है। Django प्रवास केवल स्कीमा को बदल रहा है।


1
कुछ स्क्रिप्ट चलाना वास्तव में मेरे लिए कोई विकल्प नहीं है। मेरे पास डेटाबेस के कई उदाहरण हैं और निरंतर परिनियोजन प्रक्रिया को बस "मैनेजमेड माइग्रेट" कहते हैं। यह प्रश्न पहले से ही मान्य उत्तर है जो ठीक काम करता है।
गुइतली
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.