Menulis perpindahan basisdataLink to this heading
Dokumen ini menjelaskan bagaimana menyusun dan menulis perpindahan basisdata untuk skenario berbeda anda mungkin hadapi. Untuk bahan perkenalan pada perpindahan, lihat the topic guide.
Perpindahan data dan banyak basisdataLink to this heading
Ketika menggunakan banyak basisdata, anda mungkin butuh memahami apakat atau tidak menjalankan perpindahan terhadap basisdata tertentu. Sebagai contoh, anda ingin hanya menjalankan perpindahan pada basisdata tertentu.
Untuk melakukan itu anda dapat memeriksa nama lain hubungan basisdata didalam operasi RunPython dengan mencari atribut schema_editor.connection.alias:
from django.db import migrations
def forwards(apps, schema_editor):
if not schema_editor.connection.alias == 'default':
return
# Your migration code goes here
class Migration(migrations.Migration):
dependencies = [
# Dependencies to other migrations
]
operations = [
migrations.RunPython(forwards),
]
Anda dapat juga menyediakan bayangan yang akan dilewatkan ke cara allow_migrate() dari router basisdata sebagai **hints:
myapp/dbrouters.pyclass MyRouter(object):
def allow_migrate(self, db, app_label, model_name=None, **hints):
if 'target_db' in hints:
return db == hints['target_db']
return True
Kemudian, untuk mempengaruhi ini dalam pemindahan anda, lakukan berikut:
from django.db import migrations
def forwards(apps, schema_editor):
# Your migration code goes here
...
class Migration(migrations.Migration):
dependencies = [
# Dependencies to other migrations
]
operations = [
migrations.RunPython(forwards, hints={'target_db': 'default'}),
]
Jika operasi `RunPython` atau RunSQL anda hanya berpengaruh pada satu model, adalah latihan bagus untuk melewatkan model_name sebagai sebuah bayangan untuk membuatnya se transparan mungkin ke router. Ini khususnya penting untuk aplikasi digunakan kembali dan pihak ketiga.
Perpindahan yang menambah bidang unikLink to this heading
Memberlakukan perpindahan "plain" yang menambahkan bidang bukan null unik ke sebuah tabel dengan baris yang ada akan menampilkan sebuah kesalahan karena nilai digunakan untuk mengumpulkan baris-baris yang ada dibangkitkan hanya sekali, demikian merusak pembatas unik.
Karena itu, langkah-langkah berikut harus diambil. Dalam contoh ini, kami akan menambahkan UUIDField bukan null dengan nilai awal. Rubah bidang masing-masing menurut kebutuhan anda.
Tambah bidang pada model anda dengan argumen
default=uuid.uuid4danunique=True(pilih awal yang sesuai untuk jenis dari bidang anda sedang tambahkan).Jalankan perintah
makemigrations. Ini harus membangkitkan perpindahan dengan tindakanAddField.Bangkitkan dua berkas-berkas perpindahan kosong untuk aplikasi sama dengan menjalankan
makemigrations myapp --emptydua kali. Kami telah menamai kembali berkas-berkas perpindahan untuk memberikan mereka nama berarti di contoh dibawah.Salin operasi
AddFielddari perpindahan dibangkitkan otomatis (pertama dari tiga berkas-berkas baru) ke perpindahan terakhir dan rubahAddFieldkeAlterField. Sebagi contoh:0006_remove_uuid_null.py# -*- coding: utf-8 -*- # Generated by Django A.B on YYYY-MM-DD HH:MM from __future__ import unicode_literals from django.db import migrations, models import uuid class Migration(migrations.Migration): dependencies = [ ('myapp', '0005_populate_uuid_values'), ] operations = [ migrations.AlterField( model_name='mymodel', name='uuid', field=models.UUIDField(default=uuid.uuid4, unique=True), ), ]Sunting berkas perpindahan pertama. Kelas perpindahan dibangkitkan harus kelihatan mirip seperti ini:
0004_add_uuid_field.pyclass Migration(migrations.Migration): dependencies = [ ('myapp', '0003_auto_20150129_1705'), ] operations = [ migrations.AddField( model_name='mymodel', name='uuid', field=models.UUIDField(default=uuid.uuid4, unique=True), ), ]Rubah
unique=Truemenjadinull=True-- ini akan membuat perantara bidang null dan menunda pembuatan pembatas unik sampai kami telah mengumpulkan nilai-nilai unik pada semua baris.Dalam berkas perpindahan kosong pertama, tambah tindakan
RunPythonatauRunSQLuntuk membangkitkan nilai unik (UUID dalam contoh) untuk setiap baris yang ada. Sebagai contoh:0005_populate_uuid_values.py# -*- coding: utf-8 -*- # Generated by Django A.B on YYYY-MM-DD HH:MM from __future__ import unicode_literals from django.db import migrations, models import uuid def gen_uuid(apps, schema_editor): MyModel = apps.get_model('myapp', 'MyModel') for row in MyModel.objects.all(): row.uuid = uuid.uuid4() row.save() class Migration(migrations.Migration): dependencies = [ ('myapp', '0004_add_uuid_field'), ] operations = [ # omit reverse_code=... if you don't want the migration to be reversible. migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop), ]Sekarang anda dapat berlakukan perpindahan seperti biasa dengan perintah
migrateCatat ada kondisi jarang jika anda mengizinkan obyek untuk dibuat selagi perpindahan ini berjalan. Obyek dibuat setelah
AddFielddan sebelumRunPythonakan mempunyaiuuidasli mereka ditulis kembali.
Mengendalikan urutan dari pemindahanLink to this heading
Django menentukan urutan dalam perpindahan mana harus diberlakukan tidak berdasarkan nama berkas dari setiap perpindahan, tetapi dengan membangun sebauh grafik menggunakan dua alat pada kelas Migration: dependencies dan run_before.
Jika anda telah menggunakan perintah makemigrations anda mungkin seudah melihat dependencies dalam tindakan karena perpindahan dibuat-otomatis mempunyai penentuan ini sebagai bagian dari pengolahan pembuatan mereka.
Properti dependencies diumumkan seperti ini:
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('myapp', '0123_the_previous_migration'),
]
Biasanya ini akan cukup, tetapi dari waktu ke waktu anda mungkin butuh memastikan bahwa perpindahan anda berjalan sebelum perpindahan lain. Ini berguna, sebagai contoh, untuk membuat perpindahan aplikasi pihak ketiga berjalan setelah pergantian AUTH_USER_MODEL anda.
Untuk mencapai ini, tempatkan semua perpindahan yang harus tergantung pada diri anda dalam atribut run_before pada kelas Migration anda.
class Migration(migrations.Migration):
...
run_before = [
('third_party_app', '0001_do_awesome'),
]
Lebih suka menggunakan dependencies daripada run_before ketika memungkinkan. Anda harus hanya menggunakan run_before jika dia tidak diinginkan atau tidak praktis untuk menentukan dependencies dalam perpindahan yang anda ingin jalankan setelah satu anda sedang tulis.
Migrating data between third-party appsLink to this heading
You can use a data migration to move data from one third-party application to another.
If you plan to remove the old app later, you'll need to set the dependencies
property based on whether or not the old app is installed. Otherwise, you'll
have missing dependencies once you uninstall the old app. Similarly, you'll
need to catch LookupError in the apps.get_model() call that
retrieves models from the old app. This approach allows you to deploy your
project anywhere without first installing and then uninstalling the old app.
Here's a sample migration:
myapp/migrations/0124_move_old_app_to_new_app.pyfrom django.apps import apps as global_apps
from django.db import migrations
def forwards(apps, schema_editor):
try:
OldModel = apps.get_model('old_app', 'OldModel')
except LookupError:
# The old app isn't installed.
return
NewModel = apps.get_model('new_app', 'NewModel')
NewModel.objects.bulk_create(
NewModel(new_attribute=old_object.old_attribute)
for old_object in OldModel.objects.all()
)
class Migration(migrations.Migration):
operations = [
migrations.RunPython(forwards, migrations.RunPython.noop),
]
dependencies = [
('myapp', '0123_the_previous_migration'),
('new_app', '0001_initial'),
]
if global_apps.is_installed('old_app'):
dependencies.append(('old_app', '0001_initial'))
Also consider what you want to happen when the migration is unapplied. You
could either do nothing (as in the example above) or remove some or all of the
data from the new application. Adjust the second argument of the
RunPython operation accordingly.