Django / South kullanarak bir modeli yeniden adlandırmanın en kolay yolu?


141

Ben buna South'un sitesinde, Google'da ve SO'da yanıt bulmak için avlandım, ancak bunu yapmanın basit bir yolunu bulamadım.

Güney'i kullanarak bir Django modelini yeniden adlandırmak istiyorum. Aşağıdakilere sahip olduğunuzu varsayalım:

class Foo(models.Model):
    name = models.CharField()

class FooTwo(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Foo)

ve Foo'yu Bar'a, yani

class Bar(models.Model):
    name = models.CharField()

class FooTwo(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Bar)

Sadece adını değiştirmeye çalışıyorum, basit tutmak için Fooiçin Bar, ama görmezden foode üyesi FooTwoşimdilik.

Güney'i kullanarak bunu yapmanın en kolay yolu nedir?

  1. Muhtemelen veri taşıma yapabilirdim, ama bu oldukça ilgili görünüyor.
  2. Özel bir taşıma yazın db.rename_table('city_citystate', 'geo_citystate'), ancak bu durumda yabancı anahtarı nasıl düzeltebileceğimden emin değilim.
  3. Bilmenin daha kolay bir yolu mu?

5
Ayrıca bkz stackoverflow.com/questions/3235995/... bir adlandırma için bir model alanını bir yerine modeli .
Mekanik salyangoz

Django için optimize edilmiş çözüm> = 1.8 stackoverflow.com/questions/25091130/…
Kimyasal Programcı

Yanıtlar:


130

İlk sorunuzu cevaplamak için, basit model / tablo yeniden adlandırması oldukça basittir. Komutu çalıştırın:

./manage.py schemamigration yourapp rename_foo_to_bar --empty

(Güncelleme 2: aşağıdaki uyarıyı önlemek --autoyerine deneyin --empty. Bahşiş için @KFB'ye teşekkürler.)

Güney'in eski bir sürümünü kullanıyorsanız, startmigrationbunun yerine ihtiyacınız olacak schemamigration.

Ardından taşıma dosyasını manuel olarak düzenleyerek şuna benzer:

class Migration(SchemaMigration):

    def forwards(self, orm):
        db.rename_table('yourapp_foo', 'yourapp_bar')


    def backwards(self, orm):
        db.rename_table('yourapp_bar','yourapp_foo')   

db_tableModel sınıfınızdaki Meta seçeneğini kullanarak bunu daha kolay yapabilirsiniz . Ancak bunu her yaptığınızda, kod tabanınızın eski ağırlığını artırırsınız - sınıf adlarının tablo adlarından farklı olması, kodunuzun anlaşılmasını ve bakımını zorlaştırır. Açıklık uğruna böyle basit yeniden düzenleme yapmayı tamamen destekliyorum.

(güncelleme) Bunu sadece üretimde denedim ve geçişi uygulamaya gittiğimde garip bir uyarı aldım. O dedi:

The following content types are stale and need to be deleted:

    yourapp | foo

Any objects related to these content types by a foreign key will also
be deleted. Are you sure you want to delete these content types?
If you're unsure, answer 'no'.

Ben "hayır" cevap ve her şey iyi görünüyordu.


3
Ben --empty yerine --auto kullanarak şema geçişi oluşturarak Leopd hata iletisini önlemek mümkün. Daha sonra bir db.rename_table () çağrısına tabloların silinmesini / oluşturulmasını değiştirerek geçiş dosyasını düzenledim. Bu çok iyi işledi.
KFB

4
Bu tekniği 9/2/2011 tarihinde hatasız olarak kullandım. Belki de South'un daha yeni bir sürümü hatayla ilgili sorunu çözdü.
Chip Tol

1
Bunu güncel tuttuğunuz için teşekkür ederiz! Jian'ın aşağıdaki cevabı "send_create_signal" çağrılarını tutmanın önemli olduğunu söylüyor, bunun hakkında bilginiz var mı? Kabul ediyorsanız, örnek taşıma işleminizi güncellemeniz harika olur.
mrooney

5
Bunun, bu tablodaki dizinleri yeniden adlandırmayacağını unutmayın. İleride eski tabloyla aynı ada sahip yeni bir tablo oluşturursanız, dizin adlarının çakışmasından hata alabilirsiniz. Bu tekniği kullanıyorduk, ancak bundan böyle açıkça yeni tablo oluşturacağız, verileri taşıyacağız ve sonra eski tabloyu sileceğiz.
Jeremy Banks

3
M2M tabloları gibi otomatik olarak oluşturulan tablolardaki orijinal modele ait sütun adları da bu yöntemle taşınmaz.
spookylukey

66

Değişiklikleri yapın models.pyve ardından çalıştırın

./manage.py schemamigration --auto myapp

Geçiş dosyasını incelediğinizde, bunun bir tabloyu silip yeni bir tane oluşturduğunu görürsünüz.

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Deleting model 'Foo'                                                                                                                      
        db.delete_table('myapp_foo')

        # Adding model 'Bar'                                                                                                                        
        db.create_table('myapp_bar', (
        ...
        ))
        db.send_create_signal('myapp', ['Bar'])

    def backwards(self, orm):
        ...

Bu tam olarak istediğiniz şey değil. Bunun yerine, taşıma işlemini aşağıdaki gibi görünecek şekilde düzenleyin:

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Renaming model from 'Foo' to 'Bar'                                                                                                                      
        db.rename_table('myapp_foo', 'myapp_bar')                                                                                                                        
        if not db.dry_run:
            orm['contenttypes.contenttype'].objects.filter(
                app_label='myapp', model='foo').update(model='bar')

    def backwards(self, orm):
        # Renaming model from 'Bar' to 'Foo'                                                                                                                      
        db.rename_table('myapp_bar', 'myapp_foo')                                                                                                                        
        if not db.dry_run:
            orm['contenttypes.contenttype'].objects.filter(app_label='myapp', model='bar').update(model='foo')

İfadenin yokluğunda update, db.send_create_signalçağrı ContentTypeyeni model adıyla yeni bir yaratacaktır . Ama sadece daha iyidir durumda (a yoluyla örneğin veritabanı o işaret nesneler vardır zaten var ).updateContentTypeGenericForeignKey

Ayrıca, yeniden adlandırılan modele yabancı anahtar olan bazı sütunları yeniden adlandırdıysanız,

db.rename_column(myapp_model, foo_id, bar_id)

2
KeyError hatası alıyorum: "'contenttypes' uygulamasından 'contenttype' modeli bu taşımada kullanılamıyor." Ayrıca, bir django_content_type tablo var, ama bir contenttypes tablo değil. (Django 1.6)
Seth

2
@Seth, ayrı bir veri geçişinde ContentType modellerinin güncellenmesini yaparak contenttypes.ContentTypeve --frozenbayrağını kullanarak dondurulmuş modellere model ekleyerek bu sorunu çözdüm ./manage.py datamigration. Örneğin: ./manage.py datamigration --frozen contenttypes myapp update_contenttypes. Ardından myapp_migrations / NNNN_update_contenttypes.py dosyasını yukarıda belirtilen içerik türü güncelleme koduyla düzenleyin.
Geoffrey Hing

@GeoffreyHing Bence parametre donma yok donmuş. south.readthedocs.io/en/latest/ormfreezing.html Ancak yardımınız için çok teşekkür ederim, gerçekten yardımcı oldu.
ccsakuweb

5

Güney bunu kendisi yapamaz - Bareskisine neyi temsil ettiğini nasıl bilebilir Foo? Bu, özel bir geçiş için yazacağım bir şey. ForeignKeyKodunuzu yukarıda yaptığınız gibi değiştirebilirsiniz ve daha sonra istediğiniz alanı ve tabloları yeniden adlandırmanız yeterlidir.

Son olarak, bunu gerçekten yapmanız gerekiyor mu? Modelleri yeniden adlandırmam gerekiyor - model adları sadece bir uygulama detayı - özellikle verbose_nameMeta seçeneğinin kullanılabilirliği göz önüne alındığında .


7
Alternatif olarak, modeli kodda yeniden adlandırın, ancak db_tableveritabanı tablosu adını aynı tutmak için Meta seçeneğini kullanın.
Daniel Roseman

@Daniel - db_tableyabancı anahtar isimleri türetmek için kullanılıp kullanılmadığını biliyor musunuz ?
Dominic Rodger

olduğuna inanıyorum. Model adını değiştirir ve db_table değerini ayarlarsanız, her şey beklendiği gibi çalışmalıdır.
Davor Lucic

1
@DanielRoseman bu tüm iş parçacığında en iyi çözümdür!
joerick

-1

Yukarıdaki Leopd çözümünü takip ettim. Ancak, bu model adlarını değiştirmedi. Kodda manuel olarak değiştirdim (ayrıca FK olarak adlandırılan ilgili modellerde). Ve başka bir güney göçü yaptı, ama --fake seçeneği ile. Bu, model ve tablo adlarının aynı olmasını sağlar.

Az önce fark ettiniz, önce model adlarını değiştirerek başlayabilir, daha sonra taşıma dosyasını uygulamadan önce düzenleyebilirsiniz. Çok daha temiz.

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.