Django - Güney kullanarak bir model alanı nasıl yeniden adlandırılır?


209

Bir modeldeki belirli alanların adını değiştirmek istiyorum:

class Foo(models.Model):
    name = models.CharField()
    rel  = models.ForeignKey(Bar)

şu şekilde değişmelidir:

class Foo(models.Model):
    full_name     = models.CharField()
    odd_relation  = models.ForeignKey(Bar)

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


7
Model alanından ziyade bir modeli yeniden adlandırmak için bkz. Stackoverflow.com/questions/2862979/… .
Mekanik salyangoz

Yanıtlar:


230

db.rename_columnİşlevi kullanabilirsiniz .

class Migration:

    def forwards(self, orm):
        # Rename 'name' field to 'full_name'
        db.rename_column('app_foo', 'name', 'full_name')




    def backwards(self, orm):
        # Rename 'full_name' field to 'name'
        db.rename_column('app_foo', 'full_name', 'name')

İlk argümanı db.rename_columntablo adıdır, bu nedenle Django'nun tablo adlarını nasıl oluşturduğunu hatırlamak önemlidir :

Django, veritabanı tablosunun adını model sınıfınızın ve onu içeren uygulamanın adından otomatik olarak türetir. Bir modelin veritabanı tablosu adı, modelin "uygulama etiketi" ne - manage.py startapp içinde kullandığınız ad - modelin sınıf adına, aralarında alt çizgiyle birleştirilerek oluşturulur.

Örneğin ProjectItem gibi bir çok-ifadeli, deve kasalı modeli adı durumda, Tablo adı olacaktır app_projectitem(diğer bir deyişle, bir alt arasına yerleştirilir olmayacak projectve itemolsa da deve kasalı vardır).


2
Bu \ \ tam_adı adı üzerinde çalışır, ancak ilişki alanında olmaz, değil mi?
Jonathan

23
ÖNEMLİ NOT: Bunu kullanacaksanız, "app_foo" nun veritabanı tablo adı olduğundan emin olun, örneğin: "mainapp_profile", "name", veritabanının eski sütun adıdır (model alan adı değil), örneğin: "user_id" ve "full_name", sütunun sahip olmasını istediğiniz yeni ad olacaktır (yine alan adı değil veritabanı sütunu). Yani: db.rename_column ('mainapp_profile', 'user_id', 'new_user_id') Ayrıca, yabancı anahtarlarla uğraşıyorsanız, yeniden adlandırma sırasında "_id" kısmına sahip olmalısınız.
Gezim

3
Bu db.rename_column'i manuel olarak yaparsanız, daha sonra işleri temizlemek için sahte bir şema göçmesi yapmanız gerekebilir. Bu, ilk önce sütunları yeniden adlandırarak değişikliği geçirir. Ardından modeli düzeltin (güncellenmiş ada sahip olmak için) ve ardından ./manage.py şema göç uygulaması --auto && ./manage.py göç uygulamasını --fake) yapın.
dr jimbob

24
Boş bir geçiş oluşturmak ve kodu içine yerleştirmek için ./manage.py schemamigration my_app renaming_column_x --empty'yi de kullanabilirsiniz
Ilian Iliev

11
--empty çok yardımcı olmaz, bunun yerine --auto kullanın ve oluşturulan geçişi değiştirin. Bu şekilde, models.py'nin bir sonraki geçişi için alanın silindiğini iddia etmez.
yasc

39

İşte yaptığım şey:

  1. Modelinizde sütun adı değişikliğini yapın (bu örnekte olurdu myapp/models.py)
  2. Çalıştırmak ./manage.py schemamigration myapp renaming_column_x --auto

Not renaming_column_xistediğiniz herhangi bir şey olabilir, bu yalnızca taşıma dosyasına açıklayıcı bir ad vermenin bir yoludur.

Bu myapp/migrations/000x_renaming_column_x.pysize eski sütununuzu silecek ve yeni bir sütun ekleyecek adlı bir dosya oluşturur .

Geçiş davranışını basit bir yeniden adlandırma olarak değiştirmek için bu dosyadaki kodu değiştirin:

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Renaming column 'mymodel.old_column_name' to 'mymodel.new_column_name'
        db.rename_column(u'myapp_mymodel', 'old_column_name', 'new_column_name')

    def backwards(self, orm):
        # Renaming column 'mymodel.new_column_name' to 'mymodel.old_column_name'
        db.rename_column(u'myapp_mymodel', 'new_column_name', 'old_column_name')

komutunuzdaki sütunun adı nedir? xveya column_x?
andilabs

Komutun bahsettiğiniz kısmı, taşımayı adlandırmak için kullanılır, istediğiniz her şey olabilir. Sütun adının, düzenleme sırasında taşıma dosyasında belirtilmesi gerekir.
donturner

2
--autoÖnce göçü oluşturmak harika bir ipucu. Geçişin yalnızca yöntemleri forwardsve backwardsyöntemleri varsa, ancak donmuş modelnesneyi içermemesi durumunda ortaya çıkan Güney ORM Dondurucu ile ilgili sorunları önler .
mwcz

South'un 'Bu alanı kaldırdığınız için bir varsayılan belirlemeniz GEREKİR' sorusunu nasıl yanıtlarım?
Bryce

3
Bu yöntemle ilgili bir sorun , sütun ile ilişkili kısıtlamalarıdb.rename_column yeniden adlandırmaz . Taşıma yine de çalışır, ancak eski sütun adının adını taşıyan kısıtlamalarınız olur. Benzersizlik kısıtlaması olan bir sütunu vardı, bu yöntemi kullanarak yeniden adlandırdım, benzersizlik kısıtlamasının hala var olduğunu ve bir hata aldığını test ettim, ancak kısıtlamanın adı hala eski sütun adını kullanıyor. Belki de açık ve yapardı ama sjh'ın çözümüne gitmeye karar verdim. db.delete_uniquedb.create_unique
Louis

15

Ben db.rename sütun hakkında bilmiyordum, kullanışlı geliyor, ancak geçmişte yeni sütun bir şema göçü olarak ekledim, sonra değerleri yeni alana taşımak için bir veri göçü, daha sonra eski sütunu kaldırmak için ikinci bir şema göçü oluşturdum


Ben de. Şema-veri-şema tekniğiyle ilgili sorun, alanlarınız / modelleriniz için farklı adlara sahip olmanızdır. Sevk görevlilerini etkinleştirmek için kanonik isimler kullanırsanız bazen bu bir sorundur ...
Jonathan

Sadece denedim ve bir isim çatışması olduğu için işe yaramadı. Ben aynı FK ama farklı bir isim vardı. Doğrulamadı. Yani, bunu yapma.
Gezim

2
@jonathan, farklı isimler istiyor! ... @pilgrim, kod yayınlamak ister misin? Bunu bu hafta birkaç kez yaptım, eğer modelleriniz doğrulamıyorsa güneyde göç oluşturmayacak.
sjh

Bu işe yarardı, ancak muhtemelen diğer insanların önerdiği 'rename_column'dan daha yavaş olurdu. MySQL "ALTER TABLE ... yeniden adlandırma sütunu" (veya ne olursa olsun) oldukça hızlı bir şekilde yapabileceğini biliyorum.
Rory

1
@Rory db.rename_columnkısıtlamaları sizin için yeniden adlandırmaz, bu yüzden bunu elle işlemeniz gerekir. Bunu yapmayı unutursanız , taşıma işlemi size bilinmedikçe eski sütun adını kullanan bir kısıtlama olması dışında çalışır. Sorunun sadece kozmetik olup olmadığı ya da kısıtlamanın manipüle edilmesi ya da düşürülmesi gereken gelecekteki bir göçte Güney'i bulamayacak mıyım. Her halükarda, burada sjh'nin önerdiği gibi yapmak güvenli bir yoldur: South'un neyi çözmesi gerektiğini bulmasına izin verebilirsiniz.
Louis

10

Django 1.7, Taşıma işlemlerini tanıttı, böylece artık taşıma işlemlerinizi yönetmek için fazladan paket yüklemenize bile gerek yok.

Modelinizi yeniden adlandırmak için önce boş taşıma oluşturmanız gerekir:

$ manage.py makemigrations <app_name> --empty

Ardından, taşıma kodunuzu şu şekilde düzenlemeniz gerekir:

from django.db import models, migrations

class Migration(migrations.Migration):

dependencies = [
    ('yourapp', 'XXXX_your_previous_migration'),
]

operations = [
    migrations.RenameField(
        model_name='Foo',
        old_name='name',
        new_name='full_name'
    ),
    migrations.RenameField(
        model_name='Foo',
        old_name='rel',
        new_name='odd_relation'
    ),
]

Ve bundan sonra koşmanız gerekiyor:

$ manage.py migrate <app_name>

5

Sadece modeli değiştirin ve makemigrations1.9'da çalıştırın

Django, tek bir alanı sildiğinizi ve oluşturduğunuzu otomatik olarak algılar ve şunu sorar:

Did you rename model.old to model.new (a IntegerField)? [y/N]

Evet deyin, doğru göç oluşturulur. Sihirli.


0
  1. southYüklü uygulamalarınıza proje ayar dosyasında ekleyin .
  2. Eklenen / değiştirilen alanı / tabloyu yorumlayın.
  3. $ manage.py Schemamigration <app_name> --initial
  4. $ manage.py migrate <app_name> --Fake
  5. Alanın yorumunu kaldırın ve değiştirilen alanı yazın
  6. $ manage.py Schemamigration --auto
  7. $ manage.py migrate <app_name>

'Pycharm' kullanıyorsanız, 'manage.py' yerine 'ctrl + shift + r' ve parametreler için 'shift' kullanabilirsiniz.

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.