Apa pendekatan yang disarankan untuk mengatur ulang riwayat migrasi menggunakan Django South?

153

Saya telah mengakumulasikan beberapa migrasi menggunakan Selatan (0.7) dan Django (1.1.2) yang mulai menghabiskan cukup banyak waktu dalam pengujian unit saya. Saya ingin mengatur ulang baseline dan memulai set migrasi baru. Saya telah meninjau dokumentasi Selatan , melakukan pencarian Google / Stackoverflow seperti biasa (mis. "Django selatan (reset ATAU hapus ATAU hapus) riwayat migrasi") dan belum menemukan sesuatu yang jelas.

Satu pendekatan yang telah saya renungkan akan melibatkan "memulai kembali" dengan "menghapus" Selatan atau "menghapus" riwayat secara manual (mis. Kosongkan tabel db, hapus file migrasi dari direktur migrasi) dan jalankan kembali,

./manage.py schemamigration southtut --initial

Jadi, jika ada yang pernah melakukan ini sebelumnya dan memiliki beberapa tips / saran, mereka akan sangat dihargai.

Glenn Snyder
sumber
terkadang Anda perlu menambahkan secara manual __init__.pykeappname/migrations
laike9m
2
Bagaimana Anda mengatur ulang migrasi di 1.7 (dengan migrasi built-in)?
Timo
1
@Timo: docs.djangoproject.com/en/dev/topics/migrations/… bisa menjadi pendekatan. Anda juga dapat menghapus migrasi / direktori dan menerbitkan kembali, ./manage.py makemigrationstetapi hal-hal buruk akan terjadi jika Anda tidak memulai dari db baru ...
Jocelyn delalande
Saya pikir squashmigrationsitu jawaban yang tepat
Julio Marins

Jawaban:

121

EDIT - Saya memberikan komentar di bawah ini di bagian atas ini karena penting untuk membacanya sebelum> jawaban yang diterima yang mengikuti @andybak

@Dominique: Saran Anda tentang mengatur ulang manage.py di selatan berbahaya dan dapat menghancurkan database jika ada aplikasi pihak ketiga yang menggunakan selatan dalam proyek, seperti yang ditunjukkan oleh @thnee di bawah ini. Karena jawaban Anda memiliki begitu banyak upvotes, saya akan sangat menghargai jika Anda dapat mengeditnya dan menambahkan setidaknya peringatan tentang ini, atau (bahkan lebih baik) mengubahnya untuk mencerminkan pendekatan @hobs (yang sama nyamannya, tetapi tidak mempengaruhi aplikasi lain) - terima kasih! - chrisv 26 Maret 13 jam 9:09

Jawaban yang diterima mengikuti di bawah ini:

Pertama, sebuah jawaban oleh penulis Selatan :

Selama Anda berhati-hati melakukannya pada semua penyebaran secara bersamaan, seharusnya tidak ada masalah dengan ini. Secara pribadi, saya akan melakukan:

    rm -r appname/migrations/ 
    ./manage.py reset south 
    ./manage.py convert_to_south appname 

(Perhatikan bahwa bagian " reset south" menghapus catatan migrasi untuk SEMUA aplikasi, jadi pastikan Anda menjalankan dua baris lainnya untuk semua aplikasi atau menghapus secara selektif).

The convert_to_southpanggilan di akhir membuat migrasi baru dan palsu-berlaku itu (karena database Anda sudah memiliki yang sesuai tabel). Tidak perlu membuang semua tabel aplikasi selama proses berlangsung.

Inilah yang saya lakukan di server produksi dev + saya ketika saya harus menyingkirkan semua migrasi dev yang tidak dibutuhkan ini:

  1. Pastikan kami memiliki skema DB yang sama di kedua sisi
  2. hapus setiap folder migrasi di kedua sisi
  3. jalankan ./manage.py setel ulang selatan (seperti yang dikatakan tulisan) di kedua sisi = kosongkan tabel selatan *
  4. jalankan ./manage.py convert_to_south di kedua sisi (memalsukan migrasi 0001)
  5. maka saya dapat memulai kembali untuk melakukan migrasi dan mendorong folder migrasi di server saya

* kecuali jika Anda ingin membersihkan hanya satu aplikasi di antara yang lain, jika demikian Anda perlu mengedit tabel south_history dan hanya menghapus entri tentang aplikasi Anda.

Dominique Guardiola
sumber
2
Sebagai catatan, tanggapan penulis Selatan adalah sebagai berikut: Selama Anda berhati-hati melakukannya pada semua penyebaran secara bersamaan, seharusnya tidak ada masalah dengan ini. Secara pribadi, saya akan lakukan: rm -r appname / migrations / ./manage.py reset selatan ./manage.py convert_to_south appname (Perhatikan bahwa bagian "reset selatan" menghapus catatan migrasi untuk SEMUA aplikasi, jadi pastikan Anda menjalankannya dua baris lainnya untuk semua aplikasi atau hapus secara selektif).
Adriaan Tijsseling
2
Perhatikan juga bahwa jika Anda menjatuhkan tabel, maka Anda perlu manage.py schemamigration app name --initialalih-alih convert_to_south.
Adriaan Tijsseling
7
Pada Django 1.5, perintah manajemen "reset" hilang. Sebaliknya, Anda akan ingin melakukan sesuatu yang kurang lebih seperti south.models.MigrationHistory.objects.all().delete().
Andrew B.
13
@Dominique: saran Anda mengenai manage.py reset southadalah berbahaya dan dapat merusak database jika ada aplikasi pihak ketiga yang menggunakan selatan dalam proyek, sebagai keluar menunjuk oleh @thnee bawah. Karena jawaban Anda memiliki begitu banyak upvotes, saya akan sangat menghargai jika Anda dapat mengeditnya dan menambahkan setidaknya peringatan tentang ini, atau (bahkan lebih baik) mengubahnya untuk mencerminkan pendekatan @hobs (yang sama mudahnya, tetapi tidak mempengaruhi aplikasi lain) - terima kasih!
chrisv
3
Mengapa ini sangat dinaikkan? Anda harus hampir TIDAK PERNAH sepenuhnya menghapus tabel south_migrationhistory Anda. Itu benar-benar akan mengacaukan semua aplikasi yang bergantung dengan migrasi yang tidak ingin Anda sentuh. Jawaban Hob adalah yang benar.
Cerin
188

Jika Anda perlu mengatur ulang secara selektif (hanya untuk satu aplikasi) migrasi yang terlalu lama, ini berhasil bagi saya.

rm <app-dir>/migrations/*
python manage.py schemamigration <app-name> --initial
python manage.py migrate <app-name> 0001 --fake  --delete-ghost-migrations

Jangan lupa untuk secara manual mengembalikan dependensi pada aplikasi lain dengan menambahkan baris seperti depends_on = (("<other_app_name>", "0001_initial"),("<yet_another_app_name>", "0001_initial"))ke <app-dir>/migrations/0001_initial.pyfile Anda , sebagai atribut pertama di kelas migrasi Anda tepat di bawah class Migration(SchemaMigration):.

Anda kemudian dapat ./manage.py migrate <app-name> --fake --delete-ghost-migrationspada lingkungan lain, sesuai jawaban SO ini . Tentu saja jika Anda memalsukan penghapusan atau memalsukan, migrate zeroAnda harus menghapus secara manual setiap tabel db tersisa dengan migrasi seperti ini .

Opsi yang lebih nuklir adalah ./manage.py migrate --fake --delete-ghost-migrationspada server penyebaran langsung diikuti oleh sqldump [saya]. Kemudian pipa yang dibuang ke [my] sql pada lingkungan di mana Anda memerlukan migrasi, populasi penuh. Penistaan ​​selatan, saya tahu, tetapi bekerja untuk saya.

hobs
sumber
2
Apa yang benar-benar saya inginkan adalah "ambil model .py sebagai Injil, dan buat saya bersih mulai saat itu". Dengan demikian mempertahankan kemampuan untuk mengatur penyebaran dari awal, atau bekerja dari penyebaran yang ada.
Bryce
1
Itu yang dilakukannya.
Hobs
2
@ Oh, saya sudah DependsOnUnknownMigrationlama berpura-pura memalsukan migrasi awal yang baru. Berkat komentar Anda, saya bisa mengetahui bahwa saya harus memperbarui depends_onpernyataan di mana pun itu merujuk ke aplikasi ini. Ini benar-benar jawaban terbaik di sini. Terima kasih! :)
manu
55

Berkat jawaban Dominique Guardiola dan hobs, ini membantu saya memecahkan masalah yang sulit. Namun ada beberapa masalah dengan solusinya, ini adalah pendapat saya.

Menggunakan manage.py reset southadalah bukan ide yang baik jika Anda memiliki aplikasi pihak ketiga yang menggunakan Selatan, misalnya django-cms(pada dasarnya semua menggunakan Selatan).

reset south akan menghapus semua riwayat migrasi untuk semua aplikasi yang telah Anda instal.

Sekarang perhatikan bahwa Anda meningkatkan ke versi terbaru django-cms, itu akan berisi migrasi baru seperti 0009_do_something.py. Selatan pasti akan bingung ketika Anda mencoba menjalankan migrasi itu tanpa harus 0001melalui 0008dalam sejarah migrasi.

Jauh lebih baik / aman untuk hanya mereset hanya aplikasi yang Anda pertahankan secara selektif .


Pertama-tama, pastikan aplikasi Anda tidak memiliki desync antara migrasi pada disk, dan migrasi yang telah dijalankan pada database. Kalau tidak, akan ada sakit kepala.

1. Hapus riwayat migrasi untuk aplikasi saya

sql> delete from south_migrationhistory where app_name = 'my_app';

2. Hapus migrasi untuk aplikasi saya

$ rm -rf my_app/migrations/

3. Buat migrasi awal baru untuk aplikasi saya

$ ./manage.py schemamigration --initial my_app

4. Palsu melakukan migrasi awal untuk aplikasi saya

Ini memasukkan migrasi ke south_migrationhistorytanpa menyentuh tabel sebenarnya:

$ ./manage.py migrate --fake my_app

Langkah 3 dan 4 sebenarnya hanya varian yang lebih lama manage.py convert_to_south my_app, tapi saya lebih suka kontrol ekstra itu, dalam situasi yang rumit seperti memodifikasi database produksi.

lutut
sumber
2
Saya mengedit jawaban saya untuk memasukkan perbaikan untuk masalah yang Anda temukan (hanya menebaknya berdasarkan jawaban Anda), dan mengujinya pada basis data produksi dengan jutaan baris.
Hobs
2
Ini yang kami lakukan. Jika Anda menggunakan opsi --delete-ghost-migrasi pada langkah 4, Anda dapat meninggalkan langkah 1.
tobych
Anda harus menentukan nama aplikasi secara eksplisit ./manage.py migrate --fakejika Anda tidak ingin memalsukan migrasi aplikasi lain yang menunggu migrasi.
wadim
2
@wadim Oleh karena itu langkah 0: "pastikan bahwa Anda tidak memiliki sinkronisasi antara migrasi pada disk, dan migrasi yang telah dieksekusi pada database".
Lutut
@ Lutut Kanan. Mungkin perlu disebutkan bahwa Anda merujuk ke semua aplikasi yang terinstal di langkah 0. Apakah Anda tahu cara mudah untuk melakukan langkah 0?
wadim
7

Seperti thnee (lihat jawabannya), kami menggunakan pendekatan yang lebih lembut terhadap saran penulis Selatan (Andrew Godwin) yang dikutip di tempat lain di sini, dan kami memisahkan apa yang kami lakukan dengan basis kode dari apa yang kami lakukan ke database, selama penempatan , karena kami membutuhkan penyebaran agar dapat diulang:

Apa yang kami lakukan dalam kode:

# Remove all the migrations from the app
$ rm -fR appname/migrations
# Make the first migration (don't touch the database)
$ ./manage.py schemamigration appname --initial

Apa yang kami lakukan pada basis data setelah kode tersebut digunakan

# Fake the migration history, wiping out the rest
$ ./manage.py migrate appname --fake --delete-ghost-migrations
tobych
sumber
Saya pikir saya hanya melakukan hal yang sama, tetapi menghapus entri basis data secara manual, daripada menggunakan --delete_ghoist-migrasi. Cara Anda sedikit lebih baik.
wobbily_col
1

Jika Anda hanya bekerja pada mesin dev, saya menulis perintah manajemen yang melakukan cukup banyak seperti yang disarankan Dominique.

http://balzerg.blogspot.co.il/2012/09/django-app-reset-with-south.html

Berbeda dengan saran penulis selatan, ini TIDAK akan merusak aplikasi yang diinstal lainnya menggunakan selatan.

idanzalz
sumber
Dan jika, tidak seperti penulisnya, Anda ingin mempertahankan migrasi yang ada (yaitu Anda ingin mengatur ulang aplikasi serta riwayat migrasi, tetapi tetap menggunakan migrasi yang sebenarnya), maka Anda dapat mencoba ini: goo.gl/0ZnWm
mgalgs
1

Mengikuti hanya jika Anda ingin mengatur ulang semua aplikasi. Harap cadangkan semua basis data Anda sebelum pekerjaan itu. Catat juga depend_on Anda di file awal jika ada.

Untuk sekali:

(1) find . -type d -name migrations -exec git rm -rf '{}' \;
(2) find . -type d -name migrations -exec rm -rf '{}' \;
(3) ./manage.py schemamigration <APP_NAME> --initial
(4) [GIT COMMIT]

Uji bootstrap proyek Anda sebelum mendorong. Kemudian, untuk setiap mesin lokal / jarak jauh, terapkan sebagai berikut:

(5) [GIT PULL]
(6) ./manage.py reset south
(7) ./manage.py migrate --fake

Lakukan inisial (3) untuk setiap aplikasi yang ingin Anda libatkan kembali. Perhatikan bahwa, reset (6) hanya akan menghapus riwayat migrasi, oleh karena itu tidak berbahaya bagi perpustakaan. Migrasi palsu (7) akan mengembalikan riwayat migrasi aplikasi pihak ketiga yang diinstal.

yasc
sumber
0

hapus file yang diperlukan dari folder aplikasi

jalur contoh

 cd /usr/local/lib/python2.7/dist-packages/wiki/south_migrations

wiki -adalah aplikasi saya

Andrei Eremchuk
sumber