Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Menggali Lebih Dalam Migrasi Django

Ini adalah artikel kedua dalam seri migrasi Django kami:

  • Bagian 1:Migrasi Django:Dasar
  • Bagian 2:Menggali Lebih Dalam Migrasi Django (artikel saat ini)
  • Bagian 3:Migrasi Data
  • Video:Django 1.7 Migrasi - Dasar

Dalam artikel sebelumnya dalam seri ini, Anda telah mempelajari tentang tujuan migrasi Django. Anda telah terbiasa dengan pola penggunaan mendasar seperti membuat dan menerapkan migrasi. Sekarang saatnya untuk menggali lebih dalam ke dalam sistem migrasi dan mengintip beberapa mekanisme yang mendasarinya.

Di akhir artikel ini, Anda akan mengetahui:

  • Bagaimana Django melacak migrasi
  • Bagaimana migrasi mengetahui operasi database mana yang harus dilakukan
  • Bagaimana dependensi antarmigrasi didefinisikan

Setelah Anda membungkus kepala Anda di sekitar bagian dari sistem migrasi Django ini, Anda akan dipersiapkan dengan baik untuk membuat migrasi kustom Anda sendiri. Mari kita lompat ke bagian yang terakhir kita tinggalkan!

Artikel ini menggunakan bitcoin_tracker Proyek Django dibangun di Django Migrations:A Primer. Anda dapat membuat ulang proyek itu dengan membaca artikel itu atau mengunduh kode sumbernya:

Unduh Kode Sumber: Klik di sini untuk mengunduh kode untuk proyek migrasi Django yang akan Anda gunakan dalam artikel ini.


Bagaimana Django Mengetahui Migrasi Yang Harus Diterapkan

Mari kita rekap langkah terakhir dari artikel sebelumnya dalam seri ini. Anda membuat migrasi, lalu menerapkan semua migrasi yang tersedia dengan python manage.py migrate .Jika perintah itu berhasil dijalankan, maka tabel database Anda sekarang cocok dengan definisi model Anda.

Apa yang terjadi jika Anda menjalankan perintah itu lagi? Mari kita coba:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, historical_data, sessions
Running migrations:
  No migrations to apply.

Tidak terjadi apa-apa! Setelah migrasi telah diterapkan ke database, Django tidak akan menerapkan migrasi ini ke database tertentu itu lagi. Memastikan bahwa migrasi diterapkan hanya sekali memerlukan pelacakan migrasi yang telah diterapkan.

Django menggunakan tabel database yang disebut django_migrations . Django secara otomatis membuat tabel ini dalam database Anda saat pertama kali Anda menerapkan migrasi apa pun. Untuk setiap migrasi yang diterapkan atau dipalsukan, baris baru dimasukkan ke dalam tabel.

Misalnya, inilah tampilan tabel di bitcoin_tracker kami proyek:

ID Aplikasi Nama Diterapkan
1 contenttypes 0001_initial 05-02-2019 20:23:21.461496
2 auth 0001_initial 05-02-2019 20:23:21.489948
3 admin 0001_initial 05-02-2019 20:23:21.508742
4 admin 0002_logentry_remove... 05-02-2019 20:23:21.531390
5 admin 0003_logentry_add_ac... 05-02-2019 20:23:21.564834
6 contenttypes 0002_remove_content_... 05-02-2019 20:23:21.597186
7 auth 0002_alter_permissio... 05-02-2019 20:23:21.608705
8 auth 0003_alter_user_emai... 05-02-2019 20:23:21.628441
9 auth 0004_alter_user_user... 05-02-2019 20:23:21.646824
10 auth 0005_alter_user_last... 05-02-2019 20:23:21.661182
11 auth 0006_require_content... 05-02-2019 20:23:21.663664
12 auth 0007_alter_validator... 05-02-2019 20:23:21.679482
13 auth 0008_alter_user_user... 05-02-2019 20:23:21.699201
14 auth 0009_alter_user_last... 05-02-2019 20:23:21.718652
15 historical_data 0001_initial 05-02-2019 20:23:21.726000
16 sessions 0001_initial 05-02-2019 20:23:21.734611
19 historical_data 0002_switch_to_decimals 05-02-2019 20:30:11.337894

Seperti yang Anda lihat, ada entri untuk setiap migrasi yang diterapkan. Tabel tidak hanya berisi migrasi dari historical_data aplikasi, tetapi juga migrasi dari semua aplikasi terpasang lainnya.

Saat berikutnya migrasi dijalankan, Django akan melewati migrasi yang terdaftar di tabel database. Ini berarti, bahkan jika Anda secara manual mengubah file migrasi yang telah diterapkan, Django akan mengabaikan perubahan ini, selama sudah ada entri untuk itu dalam database.

Anda dapat mengelabui Django untuk menjalankan kembali migrasi dengan menghapus baris yang sesuai dari tabel, tetapi ini jarang merupakan ide yang baik dan dapat meninggalkan Anda dengan sistem migrasi yang rusak.



File Migrasi

Apa yang terjadi ketika Anda menjalankan python manage.py makemigrations <appname> ? Django mencari perubahan yang dibuat pada model di aplikasi Anda <appname> . Jika ditemukan, seperti model yang telah ditambahkan, maka file migrasi akan dibuat di migrations subdirektori. File migrasi ini berisi daftar operasi untuk menyelaraskan skema database Anda dengan definisi model Anda.

Catatan: Aplikasi Anda harus terdaftar di INSTALLED_APPS pengaturan, dan itu harus berisi migrations direktori dengan __init__.py mengajukan. Jika tidak, Django tidak akan membuat migrasi apapun untuknya.

migrations direktori dibuat secara otomatis saat Anda membuat aplikasi baru dengan startapp perintah manajemen, tetapi mudah dilupakan saat membuat aplikasi secara manual.

File migrasi hanya Python, jadi mari kita lihat file migrasi pertama di historical_prices aplikasi. Anda dapat menemukannya di historical_prices/migrations/0001_initial.py . Seharusnya terlihat seperti ini:

from django.db import models, migrations

class Migration(migrations.Migration):
    dependencies = []
    operations = [
        migrations.CreateModel(
            name='PriceHistory',
            fields=[
                ('id', models.AutoField(
                    verbose_name='ID',
                    serialize=False,
                    primary_key=True,
                    auto_created=True)),
                ('date', models.DateTimeField(auto_now_add=True)),
                ('price', models.DecimalField(decimal_places=2, max_digits=5)),
                ('volume', models.PositiveIntegerField()),
                ('total_btc', models.PositiveIntegerField()),
            ],
            options={
            },
            bases=(models.Model,),
        ),
    ]

Seperti yang Anda lihat, ini berisi satu kelas yang disebut Migration yang mewarisi dari django.db.migrations.Migration . Ini adalah kelas yang akan dicari dan dijalankan oleh kerangka kerja migrasi saat Anda memintanya untuk menerapkan migrasi.

Migration kelas berisi dua daftar utama:

  1. dependencies
  2. operations

Operasi Migrasi

Mari kita lihat operations daftar dulu. Tabel ini berisi operasi yang akan dilakukan sebagai bagian dari migrasi. Operasi adalah subkelas dari kelas django.db.migrations.operations.base.Operation . Berikut adalah operasi umum yang dibangun ke dalam Django:

Kelas Operasi Deskripsi
CreateModel Membuat model baru dan tabel database yang sesuai
DeleteModel Menghapus model dan menghapus tabel databasenya
RenameModel Mengganti nama model dan mengganti nama tabel databasenya
AlterModelTable Mengganti nama tabel database untuk model
AlterUniqueTogether Mengubah batasan unik model
AlterIndexTogether Mengubah indeks model
AlterOrderWithRespectTo Membuat atau menghapus _order kolom untuk model
AlterModelOptions Mengubah berbagai pilihan model tanpa mempengaruhi database
AlterModelManagers Mengubah pengelola yang tersedia selama migrasi
AddField Menambahkan bidang ke model dan kolom yang sesuai di database
RemoveField Menghapus bidang dari model dan menghapus kolom yang sesuai dari database
AlterField Mengubah definisi bidang dan mengubah kolom basis datanya jika perlu
RenameField Mengganti nama bidang dan, jika perlu, juga kolom basis datanya
AddIndex Membuat indeks dalam tabel database untuk model
RemoveIndex Menghapus indeks dari tabel database untuk model

Perhatikan bagaimana operasi diberi nama setelah perubahan yang dibuat pada definisi model, bukan tindakan yang dilakukan pada database. Saat Anda menerapkan migrasi, setiap operasi bertanggung jawab untuk menghasilkan pernyataan SQL yang diperlukan untuk database spesifik Anda. Misalnya, CreateModel akan menghasilkan CREATE TABLE Pernyataan SQL.

Di luar kotak, migrasi memiliki dukungan untuk semua basis data standar yang didukung Django. Jadi, jika Anda tetap berpegang pada operasi yang tercantum di sini, maka Anda dapat melakukan lebih banyak atau lebih sedikit perubahan apa pun pada model yang Anda inginkan, tanpa harus khawatir tentang SQL yang mendasarinya. Itu semua dilakukan untuk Anda.

Catatan: Dalam beberapa kasus, Django mungkin tidak mendeteksi perubahan Anda dengan benar. Jika Anda mengganti nama model dan mengubah beberapa bidangnya, maka Django mungkin salah mengira ini sebagai model baru.

Alih-alih RenameModel dan beberapa AlterField operasi, itu akan membuat DeleteModel dan CreateModel operasi. Alih-alih mengganti nama tabel database untuk model, itu akan menjatuhkannya dan membuat tabel baru dengan nama baru, secara efektif menghapus semua data Anda!

Biasakan untuk memeriksa migrasi yang dihasilkan dan mengujinya pada salinan database Anda sebelum menjalankannya pada data produksi.

Django menyediakan tiga kelas operasi lagi untuk kasus penggunaan tingkat lanjut:

  1. RunSQL memungkinkan Anda untuk menjalankan SQL kustom dalam database.
  2. RunPython memungkinkan Anda menjalankan kode Python apa pun.
  3. SeparateDatabaseAndState adalah operasi khusus untuk penggunaan tingkat lanjut.

Dengan operasi ini, pada dasarnya Anda dapat melakukan perubahan apa pun yang Anda inginkan pada database Anda. Namun, Anda tidak akan menemukan operasi ini dalam migrasi yang telah dibuat secara otomatis dengan makemigrations perintah manajemen.

Sejak Django 2.0, ada juga beberapa operasi khusus PostgreSQL yang tersedia di django.contrib.postgres.operations yang dapat Anda gunakan untuk menginstal berbagai ekstensi PostgreSQL:

  • BtreeGinExtension
  • BtreeGistExtension
  • CITextExtension
  • CryptoExtension
  • HStoreExtension
  • TrigramExtension
  • UnaccentExtension

Perhatikan bahwa migrasi yang berisi salah satu operasi ini memerlukan pengguna database dengan hak pengguna super.

Last but not least, Anda juga dapat membuat kelas operasi Anda sendiri. Jika Anda ingin melihat ke dalamnya, maka lihatlah dokumentasi Django tentang pembuatan operasi migrasi kustom.



Ketergantungan Migrasi

dependencies list di kelas migrasi berisi migrasi apa pun yang harus diterapkan sebelum migrasi ini dapat diterapkan.

Dalam 0001_initial.py migrasi yang Anda lihat di atas, tidak ada yang harus diterapkan sebelumnya sehingga tidak ada ketergantungan. Mari kita lihat migrasi kedua di historical_prices aplikasi. Dalam file 0002_switch_to_decimals.py , dependencies atribut Migration memiliki entri:

from django.db import migrations, models

class Migration(migrations.Migration):
    dependencies = [
        ('historical_data', '0001_initial'),
    ]
    operations = [
        migrations.AlterField(
            model_name='pricehistory',
            name='volume',
            field=models.DecimalField(decimal_places=3, max_digits=7),
        ),
    ]

Ketergantungan di atas mengatakan bahwa migrasi 0001_initial dari aplikasi historical_data harus dijalankan terlebih dahulu. Itu masuk akal, karena migrasi 0001_initial membuat tabel yang berisi bidang yang migrasi 0002_switch_to_decimals ingin berubah.

Migrasi juga dapat memiliki ketergantungan pada migrasi dari aplikasi lain, seperti ini:

class Migration(migrations.Migration):
    ...

    dependencies = [
        ('auth', '0009_alter_user_last_name_max_length'),
    ]

Ini biasanya diperlukan jika model memiliki Kunci Asing yang menunjuk ke model di aplikasi lain.

Atau, Anda juga dapat menerapkan bahwa migrasi dijalankan sebelum migrasi lain menggunakan atribut run_before :

class Migration(migrations.Migration):
    ...

    run_before = [
        ('third_party_app', '0001_initial'),
    ]

Dependensi juga dapat digabungkan sehingga Anda dapat memiliki banyak dependensi. Fungsionalitas ini memberikan banyak fleksibilitas, karena Anda dapat mengakomodasi kunci asing yang bergantung pada model dari aplikasi yang berbeda.

Opsi untuk secara eksplisit mendefinisikan ketergantungan antar migrasi juga berarti bahwa penomoran migrasi (biasanya 0001 , 0002 , 0003 , ...) tidak sepenuhnya mewakili urutan penerapan migrasi. Anda dapat menambahkan ketergantungan apa pun yang Anda inginkan dan dengan demikian mengontrol pesanan tanpa harus memberi nomor ulang semua migrasi.



Melihat Migrasi

Anda biasanya tidak perlu khawatir tentang SQL yang dihasilkan oleh migrasi. Tetapi jika Anda ingin memeriksa ulang apakah SQL yang dihasilkan masuk akal atau hanya ingin tahu seperti apa tampilannya, maka Django telah membantu Anda dengan sqlmigrate perintah manajemen:

$ python manage.py sqlmigrate historical_data 0001
BEGIN;
--
-- Create model PriceHistory
--
CREATE TABLE "historical_data_pricehistory" (
    "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
    "date" datetime NOT NULL,
    "price" decimal NOT NULL,
    "volume" integer unsigned NOT NULL
);
COMMIT;

Melakukannya akan mencantumkan kueri SQL yang mendasari yang akan dihasilkan oleh migrasi yang ditentukan, berdasarkan database di settings.py Anda mengajukan. Saat Anda melewati parameter --backwards , Django menghasilkan SQL untuk membatalkan penerapan migrasi:

$ python manage.py sqlmigrate --backwards historical_data 0001
BEGIN;
--
-- Create model PriceHistory
--
DROP TABLE "historical_data_pricehistory";
COMMIT;

Setelah Anda melihat output dari sqlmigrate untuk migrasi yang sedikit lebih rumit, Anda mungkin menyadari bahwa Anda tidak perlu membuat semua SQL ini dengan tangan!




Bagaimana Django Mendeteksi Perubahan pada Model Anda

Anda telah melihat seperti apa file migrasi dan bagaimana daftar Operation kelas mendefinisikan perubahan yang dilakukan ke database. Tetapi bagaimana tepatnya Django mengetahui operasi mana yang harus masuk ke dalam file migrasi? Anda mungkin berharap bahwa Django membandingkan model Anda dengan skema basis data Anda, tetapi bukan itu masalahnya.

Saat menjalankan makemigrations , Django tidak memeriksa database Anda. Juga tidak membandingkan file model Anda dengan versi sebelumnya. Sebagai gantinya, Django melewati semua migrasi yang telah diterapkan dan membangun status proyek seperti apa model seharusnya. Status proyek ini kemudian dibandingkan dengan definisi model Anda saat ini, dan daftar operasi dibuat, yang bila diterapkan, akan memperbarui status proyek dengan definisi model.


Bermain Catur Dengan Django

Anda dapat menganggap model Anda seperti papan catur, dan Django adalah grandmaster catur yang melihat Anda bermain melawan diri sendiri. Tetapi grandmaster tidak memperhatikan setiap gerakan Anda. Grandmaster hanya melihat papan saat Anda meneriakkan makemigrations .

Karena hanya ada satu set gerakan yang mungkin (dan grandmaster adalah seorang grandmaster), dia dapat membuat gerakan yang telah terjadi sejak terakhir kali dia melihat papan. Dia membuat beberapa catatan dan membiarkanmu bermain sampai kamu berteriak makemigrations lagi.

Saat melihat papan di lain waktu, grandmaster tidak ingat seperti apa papan catur terakhir kali, tapi dia bisa membaca catatannya tentang gerakan sebelumnya dan membangun model mental seperti apa papan catur itu.

Sekarang, ketika Anda berteriak migrations , grandmaster akan memutar ulang semua gerakan yang direkam di papan catur lain dan mencatat di spreadsheet mana catatannya telah diterapkan. Papan catur kedua ini adalah database Anda, dan spreadsheet adalah django_migrations tabel.

Analogi ini cukup pas, karena menggambarkan dengan baik beberapa perilaku migrasi Django:

  • Migrasi Django mencoba menjadi efisien: Sama seperti grandmaster berasumsi bahwa Anda membuat jumlah gerakan paling sedikit, Django akan mencoba membuat migrasi paling efisien. Jika Anda menambahkan bidang bernama A menjadi model, lalu ganti namanya menjadi B , lalu jalankan makemigrations , maka Django akan membuat migrasi baru untuk menambahkan bidang bernama B .

  • Migrasi Django memiliki batasnya: Jika Anda melakukan banyak gerakan sebelum membiarkan grandmaster melihat papan catur, maka dia mungkin tidak dapat menelusuri kembali gerakan yang tepat dari setiap bidak. Demikian pula, Django mungkin tidak muncul dengan migrasi yang benar jika Anda membuat terlalu banyak perubahan sekaligus.

  • Migrasi Django mengharapkan Anda untuk bermain sesuai aturan: Ketika Anda melakukan sesuatu yang tidak terduga, seperti mengambil bagian acak dari papan atau mengotak-atik catatan, grandmaster mungkin tidak menyadarinya pada awalnya, tetapi cepat atau lambat, dia akan mengangkat tangannya dan menolak untuk melanjutkan. Hal yang sama terjadi ketika Anda mengacaukan django_migrations tabel atau ubah skema database Anda di luar migrasi, misalnya dengan menghapus tabel database untuk suatu model.



Memahami SeparateDatabaseAndState

Sekarang setelah Anda mengetahui tentang status proyek yang Django bangun, saatnya untuk melihat lebih dekat pada operasi SeparateDatabaseAndState . Operasi ini dapat melakukan persis seperti yang tersirat dari namanya:ia dapat memisahkan status proyek (model mental yang dibangun Django) dari database Anda.

SeparateDatabaseAndState dipakai dengan dua daftar operasi:

  1. state_operations berisi operasi yang hanya diterapkan pada status proyek.
  2. database_operations berisi operasi yang hanya diterapkan ke database.

Operasi ini memungkinkan Anda melakukan segala jenis perubahan pada database Anda, tetapi Anda bertanggung jawab untuk memastikan bahwa status proyek sesuai dengan database setelahnya. Contoh kasus penggunaan untuk SeparateDatabaseAndState sedang memindahkan model dari satu aplikasi ke aplikasi lain atau membuat indeks pada database besar tanpa waktu henti.

SeparateDatabaseAndState adalah operasi lanjutan dan Anda tidak perlu pada hari pertama bekerja dengan migrasi dan mungkin tidak pernah sama sekali. SeparateDatabaseAndState mirip dengan operasi jantung. Ini membawa sedikit risiko dan bukan sesuatu yang Anda lakukan hanya untuk bersenang-senang, tetapi terkadang ini adalah prosedur yang diperlukan untuk menjaga pasien tetap hidup.




Kesimpulan

Ini menyimpulkan penyelaman mendalam Anda ke dalam migrasi Django. Selamat! Anda telah membahas cukup banyak topik lanjutan dan sekarang memiliki pemahaman yang kuat tentang apa yang terjadi di balik kap migrasi.

Anda mengetahui bahwa:

  • Django melacak migrasi yang diterapkan dalam tabel migrasi Django.
  • Migrasi Django terdiri dari file Python biasa yang berisi Migration kelas.
  • Django mengetahui perubahan mana yang harus dilakukan dari operations daftar di Migration kelas.
  • Django membandingkan model Anda dengan status proyek yang dibangunnya dari migrasi.

Dengan pengetahuan ini, Anda sekarang siap untuk menangani bagian ketiga dari seri tentang migrasi Django, di mana Anda akan mempelajari cara menggunakan migrasi data untuk membuat perubahan satu kali dengan aman pada data Anda. Tetap disini!

Artikel ini menggunakan bitcoin_tracker Proyek Django dibangun di Django Migrations:A Primer. Anda dapat membuat ulang proyek itu dengan membaca artikel itu atau mengunduh kode sumbernya:

Unduh Kode Sumber: Klik di sini untuk mengunduh kode untuk proyek migrasi Django yang akan Anda gunakan dalam artikel ini.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mengumumkan Ketersediaan Umum SQL Compliance Manager 5.9

  2. Hire or Get Hire:Model Data untuk Proses Rekrutmen

  3. 0 hingga 60 :Beralih ke pos pemeriksaan tidak langsung

  4. SQL PILIH AVG

  5. 4 Cara Mendapatkan Definisi Tampilan menggunakan Transact-SQL