Django-DB-Migrations: bekleyen tetikleyici olaylara sahip olduğundan TABLO DEĞİŞTİRİLEMEZ


122

Bir TextField'dan null = True kaldırmak istiyorum:

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

Bir şema geçişi oluşturdum:

manage.py schemamigration fooapp --auto

Bazı altbilgi sütunları içerdiğinden , taşıma işlemini çalıştırırsam şunu NULLalırım error:

django.db.utils.IntegrityError: "altbilgi" sütunu boş değerler içeriyor

Şema geçişine şunu ekledim:

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

Şimdi anlıyorum:

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

Yanlış olan ne?


1
Bu soru benzer: stackoverflow.com/questions/28429933/… ve benim için daha yararlı olan yanıtları vardı.
SpoonMeiser

Yanıtlar:


139

Bunun bir başka nedeni de NOT NULL, aslında zaten NULLdeğerlere sahip olduğu zamana bir sütun ayarlamaya çalışmanız olabilir .


7
Bunu ele almak için bir veri geçişi kullanabilir veya manuel olarak (manage.py shell) içeri girip uyumlu olmayan değerleri güncelleyebilirsiniz
mgojohn

@mgojohn Bunu nasıl yaparsınız?
pyramidface

1
@pyramidface Çok seçici değilseniz, boş değerleri django kabuğunda güncelleyebilirsiniz. Daha resmi ve test edilebilir bir şey arıyorsanız, hangi sürümleri kullandığınıza bağlıdır. Güney kullanıyorsanız, bkz: south.readthedocs.org/en/latest/tutorial/part3.html ve django geçişlerini kullanıyorsanız buradaki "veri geçişleri" bölümüne bakın: docs.djangoproject.com/en/1.8/topics/ göçler
mgojohn

131

Her geçiş bir işlemin içindedir. PostgreSQL'de tabloyu güncellememeli ve sonra tablo şemasını tek bir işlemde değiştirmemelisiniz.

Veri geçişini ve şema geçişini bölmeniz gerekir. Önce bu kodla veri geçişini oluşturun:

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

Ardından şema geçişini oluşturun:

manage.py schemamigration fooapp --auto

Artık iki işleminiz var ve iki adımda geçiş çalışmalıdır.


8
PostgreSQL, sunucuda başarısız olurken (PostgreSQL 9.1) geliştirici makinemde (PostgreSQL 9.4) hem veri hem de şema değişiklikleriyle bir geçiş gerçekleştirmeyi başardığım için muhtemelen bu tür işlemlerle ilgili davranışını değiştirdi.
Bertrand Bordage

1
Benim için neredeyse aynı. Bugüne kadar 100'den fazla geçiş (~ 20 veri geçişi dahil) için kusursuz bir şekilde çalıştı ve önündeki kopyaları kaldırarak veri taşıma ile birlikte benzersiz bir kısıtlama ekledi. PostgreSQL 10.0
LinPy hayranı

Veri geçişi için geçişte bir RunPython işlemi kullanıyorsanız, bunun son işlem olduğundan emin olmanız yeterlidir. Django, RunPython işlemi son ise kendi işlemini açacağını bilir.
Dougyfresh

1
@Dougyfresh, django'nun belgelenmiş bir özelliği mi?
guettli

Aslında bunu hiçbir yerde görmüyorum, sadece gözlemlediğim bir şeydi. docs.djangoproject.com/en/2.2/ref/migration-operations/…
Dougyfresh

9

Bu sorunu çözdüm. Veri değişikliklerini şema değişikliklerinden ayırmak için şema geçişinde db.start_transaction () ve db.commit_transaction () da kullanabilirsiniz. Muhtemelen ayrı bir veri geçişi olacak kadar temiz değil ama benim durumumda şemaya, verilere ve ardından başka bir şema geçişine ihtiyacım olacaktı, bu yüzden hepsini bir kerede yapmaya karar verdim.


7
Bu çözümle ilgili sorun şudur: db.commit_transaction () sonrasında geçişiniz başarısız olursa ne olur? Buna ihtiyacınız varsa üç geçiş kullanmayı tercih ediyorum: schema-mig, data-mig, schema-mig.
guettli

5
Bakınız: django.readthedocs.io/en/latest/ref/migration-operations.html DDL işlemlerini destekleyen veritabanlarında (SQLite ve PostgreSQL), RunPython işlemlerinde her geçiş için oluşturulan işlemlerin yanında otomatik olarak eklenen herhangi bir işlem yoktur. Bu nedenle, örneğin PostgreSQL'de, şema değişikliklerini ve RunPython işlemlerini aynı geçişte birleştirmekten kaçınmalısınız veya OperationalError: "mytable" tablosunu değiştiremezsiniz çünkü bekleyen tetikleme olayları vardır.
Iasmini Gomes

6

Operasyonlarda KISITLAMAYI BELİRTİM:

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


1

Sütun şemasını değiştiriyorsunuz. Bu altbilgi sütunu artık boş bir değer içeremez. Büyük olasılıkla, o sütun için DB'de zaten depolanan boş değerler vardır. Django, migrate komutuyla DB'nizdeki boş satırları boştan şimdiki varsayılan değere güncelleyecektir. Django, altbilgi sütununun boş bir değere sahip olduğu satırları güncellemeye ve aynı göründüğü anda şemayı değiştirmeye çalışır (emin değilim).

Sorun şu ki, değerleri güncellemeye çalıştığınız aynı sütun şemasını aynı anda değiştiremezsiniz.

Çözümlerden biri, şemayı güncelleyen geçiş dosyasını silmek olabilir. Ardından, tüm bu değerleri varsayılan değerinize güncellemek için bir komut dosyası çalıştırın. Ardından, şemayı güncellemek için geçişi yeniden çalıştırın. Bu şekilde güncelleme zaten yapılmıştır. Django geçişi yalnızca şemayı değiştiriyor.


1
Bazı komut dosyası çalıştırmak benim için pek bir seçenek değil. Veritabanının birkaç örneğine sahibim ve sürekli dağıtım süreci yalnızca "manage.py migrate" öğesini çağırıyor. Bu soru zaten iyi çalışan geçerli cevaplardır.
guettli
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.