Inilah model saya:
class GroupedModels(models.Model):
other_model_one = models.ForeignKey('app.other_model')
other_model_two = models.ForeignKey('app.other_model')
Pada dasarnya, yang saya inginkan adalah other_model
menjadi unik dalam tabel ini. Itu berarti bahwa jika ada catatan di mana other_model_one
id berada 123
, saya seharusnya tidak mengizinkan catatan lain dibuat dengan other_model_two
id sebagai 123
. Saya bisa mengesampingkan clean
saya kira tapi saya bertanya-tanya apakah Django memiliki sesuatu yang tertanam
Saya menggunakan versi 2.2.5 dengan PSQL.
Sunting: Ini bukan situasi bersama yang tidak tetap. Jika saya menambahkan catatan dengan other_model_one_id=1
dan lainnya other_model_two_id=2
, saya seharusnya tidak dapat menambahkan catatan lain dengan other_model_one_id=2
dan lainnyaother_model_two_id=1
python
django
django-models
Pittfall
sumber
sumber
Jawaban:
Saya jelaskan beberapa opsi di sini, mungkin salah satunya atau kombinasi dapat bermanfaat bagi Anda.
Utama
save
Batasan Anda adalah aturan bisnis, Anda bisa mengganti
save
metode untuk menjaga data tetap konsisten:Ubah desain
Saya menempatkan sampel yang mudah dimengerti. Anggap skenario ini:
Sekarang, Anda ingin menghindari tim bermain dengan dirinya sendiri juga tim A hanya bisa bermain dengan tim B untuk sekali (hampir aturan Anda). Anda dapat mendesain ulang model Anda sebagai:
ManyToManyField.symmetrical
Ini terlihat seperti masalah simetris , Django dapat menanganinya untuk Anda. Alih-alih membuat
GroupedModels
model, buat saja bidang ManyToManyField dengan sendirinya diOtherModel
:Inilah yang django miliki untuk skenario ini.
sumber
match_id
pada batasan unike, untuk memungkinkan tim memainkan pertandingan tanpa batas. Hapus saja bidang ini untuk membatasi pemutaran lagi.Ini bukan jawaban yang sangat memuaskan, tetapi sayangnya kebenarannya adalah tidak ada cara untuk melakukan apa yang Anda gambarkan dengan fitur bawaan yang sederhana.
Apa yang Anda gambarkan
clean
akan berhasil, tetapi Anda harus berhati-hati untuk menyebutnya secara manual karena saya pikir itu hanya secara otomatis dipanggil ketika menggunakan ModelForm. Anda mungkin dapat membuat batasan basis data yang rumit tetapi itu akan hidup di luar Django dan Anda harus menangani pengecualian basis data (yang mungkin sulit di Django ketika di tengah transaksi).Mungkin ada cara yang lebih baik untuk menyusun data?
sumber
Sudah ada jawaban bagus dari dani herrera , namun saya ingin menguraikannya lebih lanjut.
Sebagaimana dijelaskan dalam opsi kedua, solusi seperti yang disyaratkan oleh OP adalah mengubah desain dan mengimplementasikan dua kendala unik berpasangan. Analogi dengan pertandingan bola basket menggambarkan masalah dengan cara yang sangat praktis.
Alih-alih pertandingan bola basket, saya menggunakan contoh dengan permainan sepak bola (atau sepak bola). Sebuah permainan sepak bola (yang saya sebut itu
Event
) dimainkan oleh dua tim (dalam model saya tim adalahCompetitor
). Ini adalah hubungan banyak ke banyak (m:n
), dengann
terbatas pada dua dalam kasus khusus ini, prinsipnya cocok untuk jumlah yang tidak terbatas.Berikut tampilan model kami:
Suatu acara dapat:
Sekarang kita harus menyelesaikan masalah dari pertanyaan. Django secara otomatis membuat tabel perantara antara model dengan hubungan banyak ke banyak, tetapi kita dapat menggunakan model khusus dan menambahkan bidang lebih lanjut. Saya menyebut model itu
Participant
:The
ManyToManyField
memiliki opsithrough
yang memungkinkan kita untuk menentukan model menengah. Mari kita ubah itu dalam modelEvent
:Batasan unik sekarang akan secara otomatis membatasi jumlah pesaing per peristiwa menjadi dua (karena hanya ada dua peran: Rumah dan Pengunjung ).
Dalam acara tertentu (pertandingan sepak bola) hanya ada satu tim tuan rumah dan satu tim tamu. Klub (
Competitor
) dapat muncul sebagai tim tuan rumah atau sebagai tim pengunjung.Bagaimana kita mengelola semua hal ini sekarang di admin? Seperti ini:
Kami telah menambahkan
Participant
sebagai sebaris dalamEventAdmin
. Saat kami membuat yang baru,Event
kami dapat memilih tim tuan rumah dan tim tamu. Opsimax_num
membatasi jumlah entri menjadi 2, oleh karena itu tidak lebih dari 2 tim dapat ditambahkan per acara.Ini dapat di refactored untuk kasus penggunaan yang berbeda. Katakanlah acara kami adalah kompetisi renang dan alih-alih rumah dan pengunjung, kami memiliki jalur 1 hingga 8. Kami hanya memperbaiki
Participant
:Dengan modifikasi ini kita dapat memiliki acara ini:
judul: FINA 2019, final gaya punggung 50m putra,
peserta:
// dan seterusnya jalur 5 ke jalur 8 (sumber: Wikipedia
Perenang hanya bisa muncul sekali dalam panas, dan jalur hanya bisa ditempati sekali dalam panas.
Saya memasukkan kode ke GitHub: https://github.com/cezar77/competition .
Sekali lagi, semua kredit jatuh ke dani herrera. Saya harap jawaban ini memberikan nilai tambah bagi pembaca.
sumber