Tonton Sekarang Tutorial ini memiliki kursus video terkait yang dibuat oleh tim Real Python. Tonton bersama dengan tutorial tertulis untuk memperdalam pemahaman Anda:Django Migration 101
Sejak versi 1.7, Django telah datang dengan dukungan bawaan untuk migrasi basis data. Di Django, migrasi basis data biasanya berjalan seiring dengan model:kapan pun Anda membuat kode model baru, Anda juga menghasilkan migrasi untuk membuat tabel yang diperlukan dalam basis data. Namun, migrasi dapat melakukan lebih banyak hal.
Anda akan mempelajari bagaimana Django Migration bekerja dan bagaimana Anda bisa mendapatkan hasil maksimal dari mereka selama empat artikel dan satu video:
- Bagian 1:Django Migration:A Primer (artikel saat ini)
- Bagian 2:Menggali Migrasi Lebih Dalam
- Bagian 3:Migrasi Data
- Video:Django 1.7 Migrasi - primer
Dalam artikel ini, Anda akan merasa nyaman dengan migrasi Django dan mempelajari yang berikut:
- Cara membuat tabel database tanpa menulis SQL
- Cara memodifikasi database secara otomatis setelah Anda mengubah model
- Cara mengembalikan perubahan yang dibuat ke database Anda
Bonus Gratis: Klik di sini untuk mendapatkan akses ke Panduan Sumber Daya Pembelajaran Django (PDF) gratis yang menunjukkan kepada Anda tip dan trik serta perangkap umum yang harus dihindari saat membangun aplikasi web Python + Django.
Masalah Yang Dipecahkan Migrasi
Jika Anda baru mengenal Django atau pengembangan web secara umum, Anda mungkin tidak familiar dengan konsep migrasi basis data, dan mungkin tidak tampak jelas mengapa mereka merupakan ide yang bagus.
Pertama, mari kita definisikan beberapa istilah dengan cepat untuk memastikan semua orang berada di halaman yang sama. Django dirancang untuk bekerja dengan basis data relasional, disimpan dalam sistem manajemen basis data relasional seperti PostgreSQL, MySQL, atau SQLite.
Dalam database relasional, data diatur dalam tabel. Sebuah tabel database memiliki sejumlah kolom, tetapi dapat memiliki sejumlah baris. Setiap kolom memiliki tipe data tertentu, seperti string dengan panjang maksimum tertentu atau bilangan bulat positif. Deskripsi semua tabel dengan kolomnya dan tipe datanya masing-masing disebut skema database.
Semua sistem basis data yang didukung oleh Django menggunakan bahasa SQL untuk membuat, membaca, memperbarui dan menghapus data dalam basis data relasional. SQL juga digunakan untuk membuat, mengubah, dan menghapus tabel database itu sendiri.
Bekerja secara langsung dengan SQL bisa sangat rumit, jadi untuk membuat hidup Anda lebih mudah, Django hadir dengan pemetaan objek-relasional, atau disingkat ORM. ORM memetakan database relasional ke dunia pemrograman berorientasi objek. Alih-alih mendefinisikan tabel database dalam SQL, Anda menulis model Django dengan Python. Model Anda menentukan bidang basis data, yang sesuai dengan kolom di tabel basis datanya.
Berikut adalah contoh bagaimana kelas model Django dipetakan ke tabel database:
Tetapi hanya mendefinisikan kelas model dalam file Python tidak membuat tabel database secara ajaib muncul entah dari mana. Membuat tabel database untuk menyimpan model Django Anda adalah tugas dari migrasi database. Selain itu, setiap kali Anda membuat perubahan pada model Anda, seperti menambahkan bidang, database juga harus diubah. Migrasi juga menanganinya.
Berikut adalah beberapa cara migrasi Django membuat hidup Anda lebih mudah.
Membuat Perubahan Basis Data Tanpa SQL
Tanpa migrasi, Anda harus terhubung ke database dan mengetikkan sekumpulan perintah SQL atau menggunakan alat grafis seperti PHPMyAdmin untuk memodifikasi skema database setiap kali Anda ingin mengubah definisi model.
Di Django, migrasi terutama ditulis dalam Python, jadi Anda tidak perlu mengetahui SQL apa pun kecuali Anda memiliki kasus penggunaan yang benar-benar canggih.
Menghindari Pengulangan
Membuat model dan kemudian menulis SQL untuk membuat tabel database karena itu akan berulang.
Migrasi dihasilkan dari model Anda, memastikan Anda tidak mengulanginya sendiri.
Memastikan Definisi Model dan Skema Basis Data Tersinkronisasi
Biasanya, Anda memiliki beberapa contoh database, misalnya satu database untuk setiap pengembang di tim Anda, database untuk pengujian, dan database dengan data langsung.
Tanpa migrasi, Anda harus melakukan perubahan skema apa pun pada setiap database Anda, dan Anda harus melacak perubahan mana yang telah dilakukan pada database mana.
Dengan Django Migrations, Anda dapat dengan mudah menyimpan banyak basis data sinkron dengan model Anda.
Melacak Perubahan Skema Basis Data di Kontrol Versi
Sistem kontrol versi, seperti Git, sangat baik untuk kode, tetapi tidak untuk skema database.
Karena migrasi adalah Python biasa di Django, Anda dapat menempatkannya dalam sistem kontrol versi sama seperti bagian kode lainnya.
Sekarang, semoga Anda yakin bahwa migrasi adalah alat yang berguna dan kuat. Mari mulai belajar cara melepaskan kekuatan itu.
Menyiapkan Proyek Django
Sepanjang tutorial ini, Anda akan mengerjakan aplikasi pelacak Bitcoin sederhana sebagai proyek contoh.
Langkah pertama adalah menginstal Django. Inilah cara Anda melakukannya di Linux atau macOS X menggunakan lingkungan virtual:
$ python3 -m venv env
$ source env/bin/activate
(env) $ pip install "Django==2.1.*"
...
Successfully installed Django-2.1.3
Sekarang Anda telah membuat lingkungan virtual baru dan mengaktifkannya, serta menginstal Django di lingkungan virtual itu.
Perhatikan bahwa pada Windows, Anda akan menjalankan env/bin/activate.bat
alih-alih source env/bin/activate
untuk mengaktifkan lingkungan virtual Anda.
Agar lebih mudah dibaca, contoh konsol tidak akan menyertakan (env)
bagian dari prompt mulai sekarang.
Dengan Django terinstal, Anda dapat membuat proyek menggunakan perintah berikut:
$ django-admin.py startproject bitcoin_tracker
$ cd bitcoin_tracker
$ python manage.py startapp historical_data
Ini memberi Anda proyek sederhana dan aplikasi bernama historical_data
. Anda sekarang harus memiliki struktur direktori ini:
bitcoin_tracker/
|
├── bitcoin_tracker/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
|
├── historical_data/
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations/
│ │ └── __init__.py
| |
│ ├── models.py
│ ├── tests.py
│ └── views.py
|
└── manage.py
Di dalam bitcoin_tracker
direktori, ada dua sub-direktori:bitcoin_tracker
untuk file di seluruh proyek dan historical_data
berisi file untuk aplikasi yang Anda buat.
Sekarang, untuk membuat model, tambahkan kelas ini di historical_data/models.py
:
class PriceHistory(models.Model):
date = models.DateTimeField(auto_now_add=True)
price = models.DecimalField(max_digits=7, decimal_places=2)
volume = models.PositiveIntegerField()
Ini adalah model dasar untuk melacak harga Bitcoin.
Juga, jangan lupa untuk menambahkan aplikasi yang baru dibuat ke settings.INSTALLED_APPS
. Buka bitcoin_tracker/settings.py
dan tambahkan historical_data
ke daftar INSTALLED_APPS
, seperti ini:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'historical_data',
]
Pengaturan lain baik-baik saja untuk proyek ini. Tutorial ini mengasumsikan bahwa proyek Anda dikonfigurasi untuk menggunakan database SQLite, yang merupakan default.
Membuat Migrasi
Dengan model yang dibuat, hal pertama yang perlu Anda lakukan adalah membuat migrasi untuknya. Anda dapat melakukannya dengan perintah berikut:
$ python manage.py makemigrations historical_data
Migrations for 'historical_data':
historical_data/migrations/0001_initial.py
- Create model PriceHistory
Catatan: Menentukan nama aplikasi, historical_data
, adalah opsional. Meninggalkannya akan membuat migrasi untuk semua aplikasi.
Ini membuat file migrasi yang menginstruksikan Django tentang cara membuat tabel database untuk model yang didefinisikan dalam aplikasi Anda. Mari kita lihat lagi pohon direktori:
bitcoin_tracker/
|
├── bitcoin_tracker/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
|
├── historical_data/
│ ├── migrations/
│ │ ├── 0001_initial.py
│ │ └── __init__.py
| |
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
|
├── db.sqlite3
└── manage.py
Seperti yang Anda lihat, migrations
direktori sekarang berisi file baru:0001_initial.py
.
Catatan: Anda mungkin memperhatikan bahwa menjalankan makemigrations
perintah juga membuat file db.sqlite3
, yang berisi database SQLite Anda.
Saat Anda mencoba mengakses file database SQLite3 yang tidak ada, file tersebut akan dibuat secara otomatis.
Perilaku ini unik untuk SQLite3. Jika Anda menggunakan backend database lain seperti PostgreSQL atau MySQL, Anda harus membuat database sendiri sebelum menjalankan makemigrations
.
Anda dapat mengintip database dengan dbshell
perintah manajemen. Di SQLite, perintah untuk membuat daftar semua tabel hanyalah .tables
:
$ python manage.py dbshell
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .tables
sqlite>
Basis datanya masih kosong. Itu akan berubah ketika Anda menerapkan migrasi. Ketik .quit
untuk keluar dari shell SQLite.
Menerapkan Migrasi
Anda sekarang telah membuat migrasi, tetapi untuk benar-benar membuat perubahan apa pun dalam database, Anda harus menerapkannya dengan perintah manajemen migrate
:
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, historical_data, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying historical_data.0001_initial... OK
Applying sessions.0001_initial... OK
Ada banyak hal yang terjadi di sini! Menurut output, migrasi Anda telah berhasil diterapkan. Tapi dari mana semua migrasi lainnya berasal?
Ingat pengaturan INSTALLED_APPS
? Beberapa aplikasi lain yang terdaftar di sana juga dilengkapi dengan migrasi, dan migrate
perintah manajemen menerapkan migrasi untuk semua aplikasi yang diinstal secara default.
Lihat lagi databasenya:
$ python manage.py dbshell
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .tables
auth_group django_admin_log
auth_group_permissions django_content_type
auth_permission django_migrations
auth_user django_session
auth_user_groups historical_data_pricehistory
auth_user_user_permissions
sqlite>
Sekarang ada beberapa tabel. Nama mereka memberi Anda gambaran tentang tujuan mereka. Migrasi yang Anda buat pada langkah sebelumnya telah membuat historical_data_pricehistory
meja. Mari kita periksa menggunakan .schema
perintah:
sqlite> .schema --indent historical_data_pricehistory
CREATE TABLE IF NOT EXISTS "historical_data_pricehistory"(
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"date" datetime NOT NULL,
"price" decimal NOT NULL,
"volume" integer unsigned NOT NULL
);
.schema
perintah mencetak CREATE
pernyataan yang akan Anda jalankan untuk membuat tabel. Parameter --indent
memformatnya dengan baik. Bahkan jika Anda tidak terbiasa dengan sintaks SQL, Anda dapat melihat bahwa skema historical_data_pricehistory
tabel mencerminkan bidang PriceHistory
model.
Ada kolom untuk setiap kolom dan kolom tambahan id
untuk kunci utama, yang Django buat secara otomatis kecuali jika Anda secara eksplisit menetapkan kunci utama dalam model Anda.
Inilah yang terjadi jika Anda menjalankan migrate
perintah lagi:
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, historical_data, sessions
Running migrations:
No migrations to apply.
Tidak ada apa-apa! Django mengingat migrasi mana yang telah diterapkan dan tidak mencoba menjalankannya kembali.
Perlu dicatat bahwa Anda juga dapat membatasi migrations
perintah manajemen ke satu aplikasi:
$ python manage.py migrate historical_data
Operations to perform:
Apply all migrations: historical_data
Running migrations:
No migrations to apply.
Seperti yang Anda lihat, Django sekarang hanya menerapkan migrasi untuk historical_data
aplikasi.
Saat Anda menjalankan migrasi untuk pertama kalinya, sebaiknya terapkan semua migrasi untuk memastikan database Anda berisi tabel yang diperlukan untuk fitur yang mungkin Anda anggap remeh, seperti autentikasi pengguna dan sesi.
Mengubah Model
Model Anda tidak kaku. Model Anda akan berubah saat proyek Django Anda memperoleh lebih banyak fitur. Anda dapat menambahkan atau menghapus bidang atau mengubah jenis dan opsinya.
Saat Anda mengubah definisi model, tabel database yang digunakan untuk menyimpan model ini juga harus diubah. Jika definisi model Anda tidak cocok dengan skema basis data Anda saat ini, kemungkinan besar Anda akan mengalami django.db.utils.OperationalError
.
Jadi bagaimana Anda mengubah tabel database? Dengan membuat dan menerapkan migrasi.
Saat menguji pelacak Bitcoin Anda, Anda menyadari bahwa Anda melakukan kesalahan. Orang-orang menjual pecahan Bitcoin, jadi kolom volume
harus dari jenis DecimalField
bukannya PositiveIntegerField
.
Mari kita ubah modelnya menjadi seperti ini:
class PriceHistory(models.Model):
date = models.DateTimeField(auto_now_add=True)
price = models.DecimalField(max_digits=7, decimal_places=2)
volume = models.DecimalField(max_digits=7, decimal_places=3)
Tanpa migrasi, Anda harus mengetahui sintaks SQL untuk mengubah PositiveIntegerField
menjadi DecimalField
. Untungnya, Django akan menanganinya untuk Anda. Katakan saja untuk melakukan migrasi:
$ python manage.py makemigrations
Migrations for 'historical_data':
historical_data/migrations/0002_auto_20181112_1950.py
- Alter field volume on pricehistory
Catatan: Nama file migrasi (0002_auto_20181112_1950.py
) didasarkan pada waktu saat ini dan akan berbeda jika Anda mengikuti sistem Anda.
Sekarang Anda menerapkan migrasi ini ke database Anda:
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, historical_data, sessions
Running migrations:
Applying historical_data.0002_auto_20181112_1950... OK
Migrasi telah berhasil diterapkan, jadi Anda dapat menggunakan dbshell
untuk memverifikasi bahwa perubahan tersebut berpengaruh:
$ python manage.py dbshell
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> .schema --indent historical_data_pricehistory
CREATE TABLE IF NOT EXISTS "historical_data_pricehistory" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"date" datetime NOT NULL,
"price" decimal NOT NULL,
"volume" decimal NOT NULL
);
Jika Anda membandingkan skema baru dengan skema yang Anda lihat sebelumnya, Anda akan melihat bahwa jenis volume
kolom telah berubah dari integer
ke decimal
untuk mencerminkan perubahan volume
bidang dalam model dari PositiveIntegerField
ke DecimalField
.
Mendaftarkan Migrasi
Jika Anda ingin mengetahui migrasi apa yang ada dalam proyek Django, Anda tidak perlu menggali melalui migrations
direktori aplikasi yang Anda instal. Anda dapat menggunakan showmigrations
perintah:
$ ./manage.py showmigrations
admin
[X] 0001_initial
[X] 0002_logentry_remove_auto_add
[X] 0003_logentry_add_action_flag_choices
auth
[X] 0001_initial
[X] 0002_alter_permission_name_max_length
[X] 0003_alter_user_email_max_length
[X] 0004_alter_user_username_opts
[X] 0005_alter_user_last_login_null
[X] 0006_require_contenttypes_0002
[X] 0007_alter_validators_add_error_messages
[X] 0008_alter_user_username_max_length
[X] 0009_alter_user_last_name_max_length
contenttypes
[X] 0001_initial
[X] 0002_remove_content_type_name
historical_data
[X] 0001_initial
[X] 0002_auto_20181112_1950
sessions
[X] 0001_initial
Ini mencantumkan semua aplikasi dalam proyek dan migrasi yang terkait dengan setiap aplikasi. Juga, itu akan menempatkan X
besar di sebelah migrasi yang telah diterapkan.
Untuk contoh kecil kami, showmigrations
perintah tidak terlalu menarik, tetapi berguna ketika Anda mulai bekerja pada basis kode yang ada atau bekerja dalam tim di mana Anda bukan satu-satunya orang yang menambahkan migrasi.
Membatalkan Penerapan Migrasi
Sekarang Anda tahu cara membuat perubahan pada skema database Anda dengan membuat dan menerapkan migrasi. Pada titik tertentu, Anda mungkin ingin membatalkan perubahan dan beralih kembali ke skema database sebelumnya karena Anda:
- Ingin menguji migrasi yang ditulis seorang rekan
- Sadari bahwa perubahan yang Anda buat adalah ide yang buruk
- Bekerja pada beberapa fitur dengan perubahan database yang berbeda secara paralel
- Ingin memulihkan cadangan yang dibuat saat database masih memiliki skema lama
Untungnya, migrasi tidak harus menjadi jalan satu arah. Dalam banyak kasus, efek migrasi dapat dibatalkan dengan membatalkan penerapan migrasi. Untuk membatalkan permohonan migrasi, Anda harus memanggil migrate
dengan nama aplikasi dan nama migrasi sebelum migrasi yang ingin Anda batalkan.
Jika Anda ingin mengembalikan migrasi 0002_auto_20181112_1950
di historical_data
. Anda aplikasi, Anda harus melewati 0001_initial
sebagai argumen untuk migrations
perintah:
$ python manage.py migrate historical_data 0001_initial
Operations to perform:
Target specific migration: 0001_initial, from historical_data
Running migrations:
Rendering model states... DONE
Unapplying historical_data.0002_auto_20181112_1950... OK
Migrasi belum diterapkan, artinya perubahan pada database telah dibalik.
Membatalkan penerapan migrasi tidak menghapus file migrasinya. Lain kali Anda menjalankan migrate
perintah, migrasi akan diterapkan lagi.
Perhatian: Jangan bingung membatalkan penerapan migrasi dengan operasi pembatalan yang biasa Anda lakukan dari editor teks favorit Anda.
Tidak semua operasi database dapat sepenuhnya dikembalikan. Jika Anda menghapus bidang dari model, membuat migrasi, dan menerapkannya, Django akan menghapus masing-masing kolom dari basis data.
Membatalkan penerapan migrasi tersebut akan membuat ulang kolom, tetapi tidak akan mengembalikan data yang disimpan di kolom itu!
Saat Anda berurusan dengan nama migrasi, Django menghemat beberapa penekanan tombol dengan tidak memaksa Anda untuk mengeja seluruh nama migrasi. Hanya perlu nama yang cukup untuk mengidentifikasinya secara unik.
Pada contoh sebelumnya, itu sudah cukup untuk menjalankan python manage.py migrate historical_data 0001
.
Menamai Migrasi
Dalam contoh di atas, Django muncul dengan nama untuk migrasi berdasarkan cap waktu—sesuatu seperti *0002_auto_20181112_1950
. Jika Anda tidak puas dengan itu, Anda dapat menggunakan --name
parameter untuk memberikan nama khusus (tanpa .py
ekstensi).
Untuk mencobanya, Anda harus menghapus migrasi lama terlebih dahulu. Anda telah membatalkan penerapannya, sehingga Anda dapat menghapus file dengan aman:
$ rm historical_data/migrations/0002_auto_20181112_1950.py
Sekarang Anda dapat membuatnya kembali dengan nama yang lebih deskriptif:
$ ./manage.py makemigrations historical_data --name switch_to_decimals
Ini akan membuat migrasi yang sama seperti sebelumnya kecuali dengan nama baru 0002_switch_to_decimals
.
Kesimpulan
Anda membahas sedikit dasar dalam tutorial ini dan mempelajari dasar-dasar migrasi Django.
Untuk rekap, langkah-langkah dasar untuk menggunakan migrasi Django terlihat seperti ini:
- Membuat atau memperbarui model
- Jalankan
./manage.py makemigrations <app_name>
- Jalankan
./manage.py migrate
untuk memigrasikan semuanya atau./manage.py migrate <app_name>
untuk memigrasikan aplikasi individual - Ulangi seperlunya
Itu dia! Alur kerja ini akan berfungsi sebagian besar waktu, tetapi jika hal-hal tidak berjalan seperti yang diharapkan, Anda juga tahu cara mendaftar dan membatalkan migrasi.
Jika sebelumnya Anda membuat dan memodifikasi tabel database Anda dengan SQL tulisan tangan, Anda sekarang menjadi jauh lebih efisien dengan mendelegasikan pekerjaan ini ke migrasi Django.
Dalam tutorial berikutnya dalam seri ini, Anda akan menggali lebih dalam topik dan mempelajari bagaimana Django Migration bekerja di bawah tenda.
Bonus Gratis: Klik di sini untuk mendapatkan akses ke Panduan Sumber Daya Pembelajaran Django (PDF) gratis yang menunjukkan kepada Anda tip dan trik serta perangkap umum yang harus dihindari saat membangun aplikasi web Python + Django.
Semangat!