Django — Kondisi Kisah Ras dengan get_or_create dan batasan unik
Jangan ulangi dirimu sendiri. Pernah. Pernah. Oh, tunggu, salahku. Maaf.
Di sini, saya menumpahkan salah satu dari 101 ramuan rahasia yang kami buat untuk diminum semua orang sebelum bergabung dengan tim kami! Artinya, jika Anda menulis sesuatu yang serupa dua kali, pasti ada cara yang lebih baik untuk melakukannya.
Baru-baru ini saat kami sedang menulis layanan pengumpulan Dokumen kami, di bawah pengaruh ramuan di atas. Tujuannya adalah untuk mengumpulkan layanan pengumpulan dokumen yang lebih umum untuk mengumpulkan semua jenis dokumen pengguna. Saya akan berbicara tentang bagaimana kami, kode kami, dan kemudian penjaga mengalami dilema aneh selama ini dan bagaimana kami menyelesaikannya.
Tabel penting dalam layanan tersebut akan berupa tabel Dokumen dengan bidang kunci, yaitu: user
, document_type (AADHAAR_CARD/PAN_CARD/SALARY_SLIP)
, dokumen. Pada awalnya, menambahkan unique_together
batasan untuk field users
, dan document_type
tampaknya logis, dengan mengingat bahwa satu pengguna hanya boleh memiliki satu Kartu Aadhaar atau PAN. Tapi itu bukan salah satu keputusan terbaik kami mengingat kami akan menyimpan slip Gaji, Pengembalian Pajak dalam tabel yang sama, yang dapat dimiliki oleh satu pengguna dalam jumlah banyak. Dengan percaya diri kami memberikan validasi pada metode penyimpanan Model Django kami seperti ini dan melanjutkan tidur dengan damai.
def save(self):
if not self.document_type not in ['AADHAAR_CARD', 'PAN_CARD']:
if Document.objects.filter(
user=self.user,
document_type=self.document_type
).exclude(id=self.id).exists():
raise ValidationError("Not allowed")
super().save()
user_aadhaar_card = None
try:
user_aadhaar_card = Document.objects.get(
user=request.user,
document_type="AADHAAR_CARD"
)
except UserDocumentMapping.DoesNotExist:
user_aadhaar_card = Document.objects.create(
user=request.user,
document_type=AADHAAR_CARD
)
try:
return some_model.get(**queryset), False
except some_model.DoesNotExist:
try:
instance = some_model.create(**queryset)
return instance, True
except IntegrityError:
return some_model.get(**queryset), False

Jadi, dengan asumsi kendala unik yang diperlukan di tempatnya, penerapan Anda akan menimbulkan kesalahan integritas, tetapi Django get_or_create
akan menangkapnya dan memberikan respons yang rapi untuk Anda.
Tetapi karena kami tidak dapat menempatkan unique_contraint apa pun di atas, dalam kasus kami, ia akan dengan senang hati membuat 2 Kartu Addhaar untuk satu pengguna (UIDAI, kode merah! get(user=user, document_type="AADHAAR_CARD")
) get_or_create
kembalikan saya tidak pernah diharapkan Banyak objek. FML!
Django 2.2 untuk menyelamatkan; Introduced UniqueConstraint
, yang memungkinkan Anda menerapkan batasan unik secara kondisional ke model Anda. Dalam kode, sesuatu yang mirip dengan:
class Document(models.Model)
user = <>
document_type = <>
document = <>
class Meta:
constraints = [
models.UniqueConstraint(
fields=['user', 'document_type'],
condition=Q(
document_type__in=["AADHAAR_CARD", "PAN_CARD"]
),
name='unique_user_unique_document_type'
)
]
Menjelang akhir, moral dari cerita ini adalah untuk -
Jangan pernah menggunakan get_or_create
atau logika serupa dengan pencarian yang tidak "unik-dibatasi" pada tingkat database!