Django — เรื่องราวของเงื่อนไขการแข่งขันพร้อม get_or_create และข้อจำกัดที่ไม่เหมือนใคร
อย่าทำซ้ำตัวเอง เคย. เคย. เดี๋ยวก่อน ยัยตัวร้าย เสียใจ.
ที่นี่ ฉันทำยาลับ 101 ชนิดที่เราให้ทุกคนดื่มก่อนเข้าร่วมทีม! หมายความว่าหากคุณเขียนสิ่งที่คล้ายกันสองครั้ง จะต้องมีวิธีที่ดีกว่าในการเขียนสิ่งนั้น
เมื่อเร็ว ๆ นี้ในขณะที่เรากำลังเขียนบริการรวบรวมเอกสารภายใต้ผลกระทบของยาข้างต้น จุดมุ่งหมายคือการรวบรวมบริการรวบรวมเอกสารทั่วไปเพื่อรวบรวมเอกสารผู้ใช้ทุกประเภท ฉันจะพูดถึงวิธีการที่เรา รหัสของเรา และจากนั้นทหารยามก็เข้าสู่ภาวะที่กลืนไม่เข้าคายไม่ออกแปลก ๆ ในช่วงเวลานี้ และวิธีที่เราแก้ปัญหานั้น
ตารางที่สำคัญในบริการดังกล่าวจะเป็นตารางเอกสารที่มีฟิลด์สำคัญ ได้แก่user
, document_type (AADHAAR_CARD/PAN_CARD/SALARY_SLIP)
, document ในตอนแรก การเพิ่มunique_together
ข้อจำกัดสำหรับฟิลด์users
และdocument_type
ดูสมเหตุสมผล โปรดทราบว่าผู้ใช้หนึ่งคนควรมีการ์ด Aadhaar หรือ PAN เพียงใบเดียว แต่มันไม่ใช่หนึ่งในการตัดสินใจที่ดีที่สุดของเรา เนื่องจากเราจะบันทึกสลิปเงินเดือน ใบคืนภาษี ไว้ในตารางเดียวกัน ซึ่งผู้ใช้ 1 คนสามารถมีได้หลายปริมาณ เราตรวจสอบวิธีการบันทึกของ Django Model ของเราอย่างมั่นใจและเข้านอนอย่างสงบสุข
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
![](https://post.nghiatu.com/assets/images/m/max/724/1*-aXqK4i2zOUTjb93Sfdskg.jpeg)
ดังนั้น หากมีข้อ จำกัด เฉพาะที่จำเป็นในตำแหน่งนั้น การนำไปใช้งานของคุณจะทำให้เกิดข้อผิดพลาดด้านความสมบูรณ์ แต่ Django get_or_create
จะตรวจจับและตอบสนองอย่างเรียบร้อยสำหรับคุณ
แต่เนื่องจากเราไม่สามารถใส่ unique_contraint ด้านบนได้ ในกรณีของเรา มันจะสร้างการ์ด Addhaar 2 ใบสำหรับผู้ใช้คนเดียวอย่างมีความสุข (UIDAI, รหัสแดง!) และครั้งต่อไปเมื่อฉันมั่นใจที่จะเรียกใช้get(user=user, document_type="AADHAAR_CARD")
ฟังก์ชันทำความสะอาดที่ไม่ดีของฉันและ Django get_or_create
ก็จะทำ คืนฉันไม่เคยคาดหวังหลายวัตถุ เอฟเอ็ม!
Django 2.2 เพื่อช่วยเหลือ; แนะนำUniqueConstraint
ซึ่งช่วยให้คุณสามารถใช้ข้อจำกัดเฉพาะอย่างมีเงื่อนไขกับโมเดลของคุณ ในโค้ด สิ่งที่คล้ายกับ:
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'
)
]
ตอนจบ คติธรรมของเรื่องคือ...
ไม่เคยใช้get_or_create
หรือตรรกะที่คล้ายกันกับการค้นหาที่ไม่ "จำกัดเฉพาะ" ในระดับฐานข้อมูล!