Saya berencana untuk mengganti nama beberapa model dalam proyek Django yang ada di mana ada banyak model lain yang memiliki hubungan kunci asing dengan model yang ingin saya ganti namanya. Saya cukup yakin ini akan membutuhkan banyak migrasi, tetapi saya tidak yakin prosedurnya.
Katakanlah saya mulai dengan model-model berikut dalam aplikasi Django bernama myapp
:
class Foo(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Foo)
is_ridonkulous = models.BooleanField()
Saya ingin mengganti nama Foo
model karena namanya tidak benar-benar masuk akal dan menyebabkan kebingungan dalam kode, dan Bar
akan membuat nama yang jauh lebih jelas.
Dari apa yang saya baca dalam dokumentasi pengembangan Django, saya mengasumsikan strategi migrasi berikut:
Langkah 1
Ubah models.py
:
class Bar(models.Model): # <-- changed model name
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
foo = models.ForeignKey(Bar) # <-- changed relation, but not field name
is_ridonkulous = models.BooleanField()
Perhatikan AnotherModel
nama bidang untuk foo
tidak berubah, tetapi relasi diperbarui ke Bar
model. Alasan saya adalah bahwa saya tidak boleh mengubah terlalu banyak sekaligus dan bahwa jika saya mengubah nama bidang ini menjadi bar
risiko kehilangan data di kolom itu.
Langkah 2
Buat migrasi kosong:
python manage.py makemigrations --empty myapp
Langkah 3
Edit Migration
kelas dalam file migrasi yang dibuat pada langkah 2 untuk menambahkan RenameModel
operasi ke daftar operasi:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.RenameModel('Foo', 'Bar')
]
Langkah 4
Terapkan migrasi:
python manage.py migrate
Langkah 5
Edit nama bidang terkait di models.py
:
class Bar(models.Model):
name = models.CharField(unique=True, max_length=32)
description = models.TextField(null=True, blank=True)
class AnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_awesome = models.BooleanField()
class YetAnotherModel(models.Model):
bar = models.ForeignKey(Bar) # <-- changed field name
is_ridonkulous = models.BooleanField()
Langkah 6
Buat migrasi kosong lain:
python manage.py makemigrations --empty myapp
Langkah 7
Edit Migration
kelas dalam file migrasi yang dibuat pada langkah 6 untuk menambahkan RenameField
operasi untuk nama bidang terkait ke daftar operasi:
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_rename_fields'), # <-- is this okay?
]
operations = [
migrations.RenameField('AnotherModel', 'foo', 'bar'),
migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]
Langkah 8
Terapkan migrasi ke-2:
python manage.py migrate
Selain memperbarui sisa kode (tampilan, formulir, dll.) Untuk mencerminkan nama variabel baru, apakah ini pada dasarnya bagaimana fungsi migrasi baru akan bekerja?
Juga, ini sepertinya banyak langkah. Bisakah operasi migrasi dikondensasi dengan cara tertentu?
Terima kasih!
sumber
apps.get_model
. Butuh banyak waktu untuk memikirkannya../manage.py makemigrations myapp
perintah itu akan menanyakan apakah Anda mengganti nama model Anda. Misalnya: Apakah Anda mengganti nama model myapp.Foo ke Bar? [y / T] Jika Anda menjawab 'y' migrasi Anda akan berisimigration.RenameModel('Foo', 'Bar')
jumlah yang sama untuk bidang yang diubah namanya :-)manage.py makemigrations myapp
mungkin masih gagal: "Anda mungkin harus menambahkan ini secara manual jika Anda mengubah nama model dan beberapa bidangnya sekaligus; ke autodetector, ini akan terlihat seperti Anda menghapus model dengan nama lama dan menambahkan yang baru dengan nama yang berbeda, dan migrasi yang dibuatnya akan kehilangan data apa pun di tabel lama. " Django 2.1 Documents Bagi saya, itu sudah cukup untuk membuat migrasi kosong, tambahkan model ganti nama, lalu jalankanmakemigrations
seperti biasa.Pada awalnya, saya berpikir bahwa metode Fiver bekerja untuk saya karena migrasi bekerja dengan baik hingga langkah 4. Namun, perubahan implisit 'ForeignKeyField (Foo)' menjadi 'ForeignKeyField (Bar)' tidak terkait dalam migrasi apa pun. Inilah sebabnya migrasi gagal ketika saya ingin mengganti nama bidang hubungan (langkah 5-8). Ini mungkin disebabkan oleh fakta bahwa 'AnotherModel' dan 'YetAnotherModel' saya dikirim ke aplikasi lain dalam kasus saya.
Jadi saya berhasil mengubah nama model dan bidang hubungan saya dengan mengikuti langkah-langkah di bawah ini:
Saya mengadaptasi metode dari ini dan khususnya trik otranzer.
Jadi seperti Fiver katakanlah yang kita miliki di aplikasi saya :
Dan di myotherapp :
Langkah 1:
Ubah setiap OneToOneField (Foo) atau ForeignKeyField (Foo) menjadi IntegerField (). (Ini akan menjaga id dari objek Foo terkait sebagai nilai integerfield).
Kemudian
Langkah 2: (Seperti langkah 2-4 dari Fiver)
Ubah nama model
Buat migrasi kosong:
Kemudian edit seperti:
Akhirnya
Langkah 3:
Ubah Kembali IntegerField Anda () menjadi ForeignKeyField atau OneToOneField sebelumnya tetapi dengan Model Bar baru. (Integerfield sebelumnya menyimpan id, jadi Django mengerti itu dan membangun kembali koneksi, yang keren.)
Kemudian lakukan:
Sangat penting, pada langkah ini Anda harus memodifikasi setiap migrasi baru dan menambahkan ketergantungan pada migrasi Bar RenameModel Foo->. Jadi jika AnotherModel dan YetAnotherModel berada di myotherapp, migrasi yang dibuat di myotherapp harus terlihat seperti ini:
Kemudian
Langkah 4:
Akhirnya, Anda dapat mengubah nama bidang Anda
dan kemudian melakukan penggantian nama otomatis
(Django harus bertanya apakah Anda benar-benar mengganti nama modelnya, katakan ya)
Dan itu dia!
Ini berfungsi pada Django1.8
sumber
IntegerField
. Ini bekerja dengan baik untuk saya, dan memiliki keuntungan tambahan bahwa mereka dapat diciptakan kembali dengan nama yang benar. Secara alami saya akan menyarankan untuk meninjau semua migrasi sebelum benar-benar menjalankannya!ForeignKey
s untukIntegerField
menyelamatkan hari saya hari ini!Saya perlu melakukan hal yang sama dan mengikuti. Saya mengubah model sekaligus (Langkah 1 dan 5 bersamaan dari jawaban Fiver). Kemudian buat migrasi skema tetapi diedit menjadi ini:
Ini bekerja dengan sempurna. Semua data saya yang ada muncul, semua tabel lain direferensikan Bar baik.
dari sini: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/
sumber
Untuk Django 1.10, saya berhasil mengubah dua nama kelas model (termasuk ForeignKey, dan dengan data) dengan hanya menjalankan Makemigrations, dan kemudian Migrasikan untuk aplikasi. Untuk langkah Makemigrations, saya harus mengkonfirmasi bahwa saya ingin mengubah nama tabel. Migrasi mengubah nama tabel tanpa masalah.
Kemudian saya mengubah nama bidang ForeignKey agar cocok, dan sekali lagi diminta oleh Makemigrations untuk mengkonfirmasi bahwa saya ingin mengubah nama. Bermigrasi daripada melakukan perubahan.
Jadi saya mengambil ini dalam dua langkah tanpa mengedit file khusus. Saya memang mendapatkan kesalahan pada awalnya karena saya lupa mengubah file admin.py, seperti yang disebutkan oleh @wasibigeek.
sumber
Saya juga menghadapi masalah seperti yang dijelaskan oleh v.thorey dan menemukan bahwa pendekatannya sangat berguna tetapi dapat diringkas menjadi langkah-langkah yang lebih sedikit yang sebenarnya adalah langkah 5 hingga 8 seperti yang dijelaskan oleh Fiver tanpa langkah 1 hingga 4 kecuali bahwa langkah 7 perlu diubah seperti yang saya lakukan. di bawah langkah 3. Langkah-langkah keseluruhan adalah sebagai berikut:
Langkah 1: Edit nama bidang terkait di models.py
Langkah 2: Buat migrasi kosong
Langkah 3: Edit kelas Migrasi dalam file migrasi yang dibuat pada Langkah 2
Langkah 4: Terapkan migrasi
Selesai
PS Saya sudah mencoba pendekatan ini pada Django 1.9
sumber
Saya menggunakan Django versi 1.9.4
Saya telah mengikuti langkah-langkah berikut: -
Saya baru saja mengganti nama model oldName ke NewName Run
python manage.py makemigrations
. Ini akan meminta Anda untukDid you rename the appname.oldName model to NewName? [y/N]
memilih YJalankan
python manage.py migrate
dan itu akan meminta AndaJenis konten berikut ini sudah basi dan perlu dihapus:
Objek apa pun yang terkait dengan tipe konten ini dengan kunci asing juga akan dihapus. Anda yakin ingin menghapus jenis konten ini? Jika Anda tidak yakin, jawab 'tidak'.
Itu mengubah nama dan memigrasikan semua data yang ada ke tabel baru bernama untuk saya.
sumber
Sayangnya, saya menemukan masalah (masing-masing Django 1.x) dengan mengganti nama migrasi yang meninggalkan nama tabel lama dalam database.
Django bahkan tidak mencoba apa pun di atas meja lama, hanya mengganti nama modelnya sendiri. Masalah yang sama dengan kunci asing, dan indeks secara umum - perubahan di sana tidak dilacak dengan benar oleh Django.
Solusi paling sederhana (solusi):
Solusi nyata (cara mudah untuk mengganti semua indeks, batasan, pemicu, nama, dll dalam 2 komit, tetapi untuk tabel yang lebih kecil ):
komit A:
Bar
saja. (termasuk semua hubungan pada skema)Dalam persiapan migrasi
RunPython
, yang menyalin data dari Foo ke Bar (termasukid
dari Foo)melakukan B: (jangan terburu-buru, lakukan ketika seluruh tim dimigrasikan)
Foo
pembersihan lebih lanjut:
bug di Django:
sumber
Hanya ingin mengkonfirmasi dan menambahkan komentar ceasaro. Django 2.0 tampaknya melakukan ini secara otomatis sekarang.
Saya menggunakan Django 2.2.1, yang harus saya lakukan adalah mengubah nama model dan menjalankannya
makemigrations
.Di sini ia bertanya apakah saya telah mengubah nama kelas tertentu dari
A
menjadiB
, saya memilih ya dan berlari bermigrasi dan semua tampaknya berfungsi.Catatan saya tidak mengganti nama nama model lama di file apa pun di dalam folder proyek / migrasi.
sumber
Saya perlu mengganti nama beberapa tabel. Tapi hanya satu model yang diganti nama yang diperhatikan oleh Django. Itu terjadi karena Django mengulangi penambahan, lalu menghapus model. Untuk setiap pasangan memeriksa apakah mereka memiliki aplikasi yang sama dan memiliki bidang yang sama . Hanya satu tabel yang tidak memiliki kunci asing untuk diubah namanya (kunci asing berisi nama kelas model, seperti yang Anda ingat). Dengan kata lain, hanya satu tabel yang tidak memiliki perubahan bidang. Karena itulah diperhatikan.
Jadi, solusinya adalah mengubah nama satu tabel pada satu waktu, mengubah nama kelas model di
models.py
, mungkinviews.py
, dan melakukan migrasi. Setelah itu periksa kode Anda untuk referensi lain (nama kelas model, nama terkait (permintaan), nama variabel). Buat migrasi, jika perlu. Lalu, secara opsional gabungkan semua migrasi ini menjadi satu (pastikan untuk menyalin impor juga).sumber
Saya akan membuat kata-kata @ceasaro, milik saya di komentarnya pada jawaban ini .
Versi baru Django dapat mendeteksi perubahan dan bertanya tentang apa yang telah dilakukan. Saya juga akan menambahkan bahwa Django mungkin mencampur urutan pelaksanaan beberapa perintah migrasi.
Akan lebih bijaksana untuk menerapkan perubahan kecil dan menjalankan
makemigrations
danmigrate
dan jika kesalahan terjadi file migrasi dapat diedit.Beberapa baris urutan eksekusi dapat diubah untuk menghindari kesalahan.
sumber
migrations.SeparateDatabaseAndState
bisa membantu?Jika Anda menggunakan IDE yang bagus seperti PyCharm, Anda dapat mengklik kanan pada nama model dan melakukan refactor -> rename. Ini menghemat masalah Anda melalui semua kode Anda yang referensi model. Kemudian jalankan macemigrations dan bermigrasi. Django 2+ hanya akan mengonfirmasi perubahan nama.
sumber
Saya memutakhirkan Django dari versi 10 ke versi 11:
(
-U
untuk "upgrade") dan itu memecahkan masalah.sumber