Saya cukup akrab dengan Django, tetapi baru-baru ini memperhatikan ada on_delete=models.CASCADE
pilihan dengan model, saya telah mencari dokumentasi yang sama tetapi tidak dapat menemukan lebih dari:
Diubah dalam Django 1.9:
on_delete
sekarang dapat digunakan sebagai argumen posisi kedua (sebelumnya biasanya hanya dilewatkan sebagai argumen kata kunci). Ini akan menjadi argumen yang diperlukan dalam Django 2.0.
contoh kasus penggunaan adalah
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
Apa yang dilakukan on_delete? ( Saya kira tindakan yang harus dilakukan jika model dihapus )
Apa yang models.CASCADE
harus dilakukan ( ada petunjuk dalam dokumentasi )
Opsi apa lagi yang tersedia ( jika tebakan saya benar )?
Di mana dokumentasi untuk ini berada?
python
django
django-models
Semuanya
sumber
sumber
Jawaban:
Ini adalah perilaku untuk diadopsi ketika objek yang dirujuk dihapus. Ini tidak spesifik untuk Django, ini adalah standar SQL.
Ada 6 tindakan yang mungkin dilakukan ketika peristiwa tersebut terjadi:
CASCADE
: Ketika objek yang direferensikan dihapus, juga menghapus objek yang memiliki referensi untuk itu (Ketika Anda menghapus posting blog misalnya, Anda mungkin ingin menghapus komentar juga). SQL setara:CASCADE
.PROTECT
: Melarang penghapusan objek yang dirujuk. Untuk menghapusnya, Anda harus menghapus semua objek yang mereferensikannya secara manual. SQL setara:RESTRICT
.SET_NULL
: Setel referensi ke NULL (mengharuskan bidang menjadi nullable). Misalnya, ketika Anda menghapus seorang Pengguna, Anda mungkin ingin menyimpan komentar yang dia posting di posting blog, tetapi mengatakan itu diposting oleh pengguna anonim (atau dihapus). SQL setara:SET NULL
.SET_DEFAULT
: Tetapkan nilai default. SQL setara:SET DEFAULT
.SET(...)
: Tetapkan nilai yang diberikan. Yang ini bukan bagian dari standar SQL dan sepenuhnya ditangani oleh Django.DO_NOTHING
: Mungkin ide yang sangat buruk karena ini akan membuat masalah integritas di database Anda (merujuk objek yang sebenarnya tidak ada). SQL setara:NO ACTION
.Sumber: Dokumentasi Django
Lihat juga dokumentasi PostGreSQL misalnya.
Dalam kebanyakan kasus,
CASCADE
adalah perilaku yang diharapkan, tetapi untuk setiap ForeignKey, Anda harus selalu bertanya pada diri sendiri apa perilaku yang diharapkan dalam situasi ini.PROTECT
danSET_NULL
seringkali bermanfaat. Pengaturan diCASCADE
mana seharusnya tidak, berpotensi menghapus semua basis data Anda dalam kaskade, dengan hanya menghapus satu pengguna.Catatan tambahan untuk memperjelas arah kaskade
Lucu melihat bahwa arah
CASCADE
tindakannya tidak jelas bagi banyak orang. Sebenarnya, itu lucu untuk melihat bahwa hanya denganCASCADE
tindakan tidak jelas. Saya mengerti perilaku kaskade mungkin membingungkan, namun Anda harus berpikir bahwa itu adalah arah yang sama dengan tindakan lainnya . Jadi, jika Anda merasaCASCADE
arah itu tidak jelas bagi Anda, itu sebenarnya berarti bahwaon_delete
perilaku tidak jelas bagi Anda.Dalam database Anda, kunci asing pada dasarnya diwakili oleh bidang bilangan bulat yang nilainya adalah kunci utama objek asing. Katakanlah Anda memiliki entri comment_A , yang memiliki kunci asing untuk entri article_B . Jika Anda menghapus entri comment_A , semuanya baik-baik saja, article_B digunakan untuk hidup tanpa comment_A dan jangan repot-repot jika itu dihapus. Namun, jika Anda menghapus article_B , maka comment_A panik! Itu tidak pernah hidup tanpa article_B dan membutuhkannya, itu adalah bagian dari atributnya (
article=article_B
, tapi apa itu * article_B ** ???). Di sinilahon_delete
langkah-langkahnya, untuk menentukan cara mengatasi kesalahan integritas ini, baik dengan mengatakan:PROTECT
dalam bahasa SQL)SET_NULL
)CASCADE
perilaku).SET_DEFAULT
, atau bahkanSET(...)
).DO_NOTHING
)Saya harap ini membuat arah kaskade menjadi lebih jelas. :)
sumber
Comment
memiliki kunci asing untukBlogPost
kemudian menghapus BlogPost harus menghapus Komentar, tetapi menghapus Komentar tidak boleh menghapus BlogPost, terlepas dari RDMS?Comment
, yang memiliki bidang FK di tabelnya, sementaraBlogPost
"memiliki"Comment
jika kita berbicara tentang model kehidupan nyata. Baik.The
on_delete
metode yang digunakan untuk memberitahu Django apa yang harus dilakukan dengan contoh model yang tergantung pada model contoh Anda hapus. (misalnyaForeignKey
hubungan). Theon_delete=models.CASCADE
memberitahu Django untuk membuat efek penghapusan yaitu melanjutkan menghapus model dependen juga.Inilah contoh yang lebih konkret. Asumsikan Anda memiliki
Author
model yang adaForeignKey
dalamBook
model. Sekarang, jika Anda menghapus instanceAuthor
model, Django tidak akan tahu apa yang harus dilakukan dengan instanceBook
model yang bergantung pada instanceAuthor
model tersebut. Theon_delete
Metode memberitahu Django apa yang harus dilakukan dalam kasus itu. Pengaturanon_delete=models.CASCADE
akan menginstruksikan Django untuk membuat efek penghapusan yaitu menghapus semuaBook
instance model yang bergantung padaAuthor
instance model yang Anda hapus.Catatan:
on_delete
akan menjadi argumen wajib dalam Django 2.0. Dalam versi yang lebih lama defaultnya adalahCASCADE
.Inilah seluruh dokumentasi resmi.
sumber
FYI,
on_delete
parameter dalam model mundur dari apa yang terdengar. Anda mengenakanon_delete
Kunci Asing (FK) pada model untuk memberi tahu Django apa yang harus dilakukan jika entri FK yang Anda tunjuk pada catatan Anda dihapus. Pilihan toko kami telah menggunakan sebagian besarPROTECT
,CASCADE
danSET_NULL
. Berikut adalah aturan dasar yang saya temukan:PROTECT
saat FK Anda menunjuk ke tabel pencarian yang benar-benar tidak boleh berubah dan yang pasti tidak menyebabkan meja Anda berubah. Jika ada yang mencoba menghapus entri pada tabel pencarian itu,PROTECT
mencegah mereka menghapusnya jika dikaitkan dengan catatan apa pun. Ini juga mencegah Django dari menghapus catatan Anda hanya karena menghapus entri pada tabel pencarian. Bagian terakhir ini sangat penting. Jika seseorang menghapus jenis kelamin "Perempuan" dari tabel Gender saya, saya PASTI TIDAK ingin itu menghapus secara instan siapa saja dan semua orang yang saya miliki di tabel Person yang memiliki jenis kelamin itu.CASCADE
saat FK Anda menunjuk ke catatan "orang tua". Jadi, jika Seseorang dapat memiliki banyak entri PersonEthnicity (dia bisa menjadi Indian Amerika, Hitam, dan Putih), dan Orang itu dihapus, saya benar - benar ingin entri PersonEthnicity "anak" dihapus. Mereka tidak relevan tanpa Pribadi.SET_NULL
ketika Anda melakukan ingin orang diizinkan untuk menghapus entri pada tabel-up, tetapi Anda masih ingin mempertahankan catatan Anda. Sebagai contoh, jika seseorang dapat memiliki HighSchool, tetapi itu tidak masalah bagi saya jika SMA itu hilang di meja saya, saya akan mengatakanon_delete=SET_NULL
. Ini akan meninggalkan catatan Orang saya di luar sana; itu hanya akan membuat FK sekolah menengah pada Orang saya menjadi nol. Jelas, Anda harus mengizinkannull=True
di FK itu.Berikut adalah contoh model yang melakukan ketiga hal:
Sebagai berita gembira terakhir, tahukah Anda bahwa jika Anda tidak menentukan
on_delete
(atau tidak), perilaku defaultnya adalahCASCADE
? Ini berarti bahwa jika seseorang menghapus entri gender pada tabel Gender Anda, setiap Orang yang mencatat gender tersebut juga akan dihapus!Saya akan berkata, "Jika ragu, atur
on_delete=models.PROTECT
." Lalu, uji aplikasi Anda. Anda akan dengan cepat mengetahui FK mana yang harus diberi label nilai-nilai lain tanpa membahayakan data Anda.Juga, perlu dicatat bahwa
on_delete=CASCADE
sebenarnya tidak ditambahkan ke migrasi Anda, jika itu adalah perilaku yang Anda pilih. Saya kira ini karena itu adalah default, jadi menempatkanon_delete=CASCADE
adalah hal yang sama dengan tidak meletakkan apa pun.sumber
Seperti disebutkan sebelumnya, CASCADE akan menghapus catatan yang memiliki kunci asing dan referensi objek lain yang telah dihapus. Jadi misalnya jika Anda memiliki situs web real estat dan memiliki Properti yang mereferensikan Kota
dan sekarang ketika Kota dihapus dari basis data, semua Properti terkait (mis. real estat yang terletak di kota itu) juga akan dihapus dari basis data
Sekarang saya juga ingin menyebutkan nilai dari opsi lain, seperti SET_NULL atau SET_DEFAULT atau bahkan DO_NOTHING. Pada dasarnya, dari perspektif administrasi, Anda ingin "menghapus" catatan-catatan itu. Tetapi Anda tidak benar-benar ingin mereka menghilang. Untuk banyak alasan. Seseorang mungkin telah menghapusnya secara tidak sengaja, atau untuk audit dan pemantauan. Dan pelaporan biasa. Jadi itu bisa menjadi cara untuk "memutuskan" properti dari Kota. Sekali lagi, itu akan tergantung pada bagaimana aplikasi Anda ditulis.
Misalnya, beberapa aplikasi memiliki bidang "dihapus" yaitu 0 atau 1. Dan semua pencarian dan tampilan daftar dll, apa pun yang dapat muncul dalam laporan atau di mana pun pengguna dapat mengaksesnya dari ujung depan, mengecualikan apa pun yang ada
deleted == 1
. Namun, jika Anda membuat laporan khusus atau permintaan khusus untuk menarik daftar catatan yang dihapus dan bahkan lebih untuk melihat kapan terakhir diubah (bidang lain) dan oleh siapa (yaitu siapa yang menghapusnya dan kapan) .. itu sangat menguntungkan dari sudut pandang eksekutif.Dan jangan lupa bahwa Anda dapat mengembalikan penghapusan tidak disengaja sesederhana
deleted = 0
untuk catatan-catatan itu.Maksud saya adalah, jika ada fungsi, selalu ada alasan di baliknya. Tidak selalu alasan yang bagus. Tapi alasan. Dan seringkali yang bagus juga.
sumber
Inilah jawaban untuk pertanyaan Anda yang mengatakan: mengapa kami menggunakan on_delete?
Ketika suatu objek yang dirujuk oleh ForeignKey dihapus, Django secara default mengemulasi perilaku kendala SQL ON DELETE CASCADE dan juga menghapus objek yang berisi ForeignKey. Perilaku ini dapat diganti dengan menetapkan argumen on_delete. Misalnya, jika Anda memiliki ForeignKey yang dapat dibatalkan dan Anda ingin agar null ditetapkan ketika objek yang dirujuk dihapus:
Nilai yang mungkin untuk on_delete ditemukan di django.db.models:
CASCADE: Cascade delete; default.
PROTECT: Mencegah penghapusan objek yang direferensikan dengan menaikkan ProtectedError, subkelas django.db.IntegrityError.
SET_NULL: Tetapkan ForeignKey null; ini hanya mungkin jika null Benar.
SET_DEFAULT: Tetapkan ForeignKey ke nilai defaultnya; default untuk ForeignKey harus ditetapkan.
sumber
Katakanlah Anda memiliki dua model, satu bernama Person dan satu lagi bernama Perusahaan .
Menurut definisi, satu orang dapat membuat lebih dari satu perusahaan.
Mengingat sebuah perusahaan dapat memiliki satu dan hanya satu orang, kami ingin ketika seseorang dihapus maka semua perusahaan yang terkait dengan orang itu juga akan dihapus.
Jadi, kita mulai dengan membuat model Person, seperti ini
Kemudian, model Perusahaan dapat terlihat seperti ini
Perhatikan penggunaan
on_delete=models.CASCADE
dalam Perusahaan model. Yaitu untuk menghapus semua perusahaan ketika orang yang memilikinya (instance dari class class) dihapus.sumber
Ubah orientasi model mental Anda dari fungsionalitas "CASCADE" dengan memikirkan untuk menambahkan FK ke kaskade yang sudah ada (yaitu air terjun). Sumber air terjun ini adalah Kunci Utama. Menghapus mengalir ke bawah.
Jadi, jika Anda mendefinisikan on_delete FK sebagai "CASCADE," Anda menambahkan catatan FK ini ke kaskade penghapusan yang berasal dari PK. Catatan FK dapat berpartisipasi dalam kaskade ini atau tidak ("SET_NULL"). Bahkan, catatan dengan FK bahkan dapat mencegah aliran penghapusan! Bangun bendungan dengan "PROTECT."
sumber
Menggunakan CASCADE berarti memberi tahu Django untuk menghapus catatan yang dirujuk. Dalam contoh aplikasi jajak pendapat di bawah ini: Ketika 'Pertanyaan' dihapus, itu juga akan menghapus Pilihan yang dimiliki Pertanyaan ini.
mis. Pertanyaan: Bagaimana Anda mendengar tentang kami? (Pilihan: 1. Teman 2. Iklan TV 3. Mesin Pencari 4. Promosi Email)
Saat Anda menghapus pertanyaan ini, itu juga akan menghapus keempat pilihan ini dari tabel. Perhatikan arah mana yang mengalir. Anda tidak harus memakai on_delete = models.CASCADE di Model Pertanyaan, masukkan ke dalam Pilihan.
sumber