ดังที่ได้กล่าวไว้ในความคิดเห็นเหตุผลที่ "พร้อมกับการตั้งค่านี้จำเป็นต้องใช้ทั้งคู่" ก็คือคุณลืมที่จะเพิ่มลงในblank=True
เขตข้อมูล FK ของคุณดังนั้นModelForm
(อย่างใดอย่างหนึ่งที่กำหนดเองหรือค่าเริ่มต้นที่สร้างโดยผู้ดูแลระบบ) จะทำให้ฟิลด์ฟอร์ม . ที่ระดับ db schema คุณสามารถเติมทั้งสองอย่างใดอย่างหนึ่งหรือทั้งหมดของ FKs เหล่านั้นมันจะโอเคตั้งแต่คุณทำให้เขตข้อมูล db เหล่านั้นเป็นโมฆะ (ด้วยnull=True
อาร์กิวเมนต์)
นอกจากนี้ (ถ้ามีความคิดเห็นอื่นของฉัน) คุณอาจต้องการตรวจสอบว่า FK ของคุณต้องการที่จะไม่ซ้ำกันจริงๆ เทคนิคนี้จะเปลี่ยนความสัมพันธ์ของคุณเป็นความสัมพันธ์แบบหนึ่งต่อหนึ่ง - คุณอนุญาตให้มีเพียงหนึ่งระเบียน 'การตรวจสอบ' สำหรับ GroupID หรือ SiteId ที่ระบุ (คุณไม่สามารถมี 'การตรวจสอบ' สองรายการขึ้นไปสำหรับ GroupId หรือ SiteId) . หากนั่นคือสิ่งที่คุณต้องการจริงๆคุณอาจต้องการใช้ OneToOneField แทนอย่างชัดเจน (db schema จะเหมือนกัน แต่ตัวแบบจะชัดเจนมากขึ้นและตัวอธิบายที่เกี่ยวข้องสามารถใช้กับกรณีการใช้งานนี้ได้มากกว่า)
หมายเหตุด้านข้าง: ในโมเดล Django ฟิลด์ ForeignKey จะปรากฏเป็นอินสแตนซ์ของโมเดลที่เกี่ยวข้องไม่ใช่ในฐานะ id ดิบ IOW ให้สิ่งนี้:
class Foo(models.Model):
name = models.TextField()
class Bar(models.Model):
foo = models.ForeignKey(Foo)
foo = Foo.objects.create(name="foo")
bar = Bar.objects.create(foo=foo)
แล้วbar.foo
จะแก้ปัญหาเพื่อไม่ให้foo
foo.id
ดังนั้นคุณต้องการเปลี่ยนชื่อInspectionID
และSiteID
เขตข้อมูลของคุณ ให้เหมาะสมinspection
และsite
แน่นอน BTW ใน Python อนุสัญญาการตั้งชื่อคือ 'all_lower_with_underscores' สำหรับสิ่งอื่นนอกเหนือจากชื่อคลาสและค่าคงที่หลอก
ตอนนี้สำหรับคำถามหลักของคุณ: ไม่มีวิธี SQL มาตรฐานเฉพาะในการบังคับใช้ข้อ จำกัด "หนึ่งหรืออื่น ๆ " ในระดับฐานข้อมูลดังนั้นจึงมักจะใช้ข้อ จำกัด การตรวจสอบซึ่งทำในรูปแบบ Django กับข้อ จำกัด เมตาของรุ่น ตัวเลือก
สิ่งนี้ถูกกล่าวว่าการสนับสนุนและบังคับใช้ข้อ จำกัด ที่ระดับ db นั้นขึ้นอยู่กับผู้ขาย DB ของคุณ (MySQL <8.0.16 เพียงแค่ไม่สนใจตัวอย่าง) และข้อ จำกัด ที่คุณต้องการที่นี่จะไม่ถูกบังคับใช้ที่ฟอร์ม หรือการตรวจสอบระดับรูปแบบเฉพาะเมื่อพยายามที่จะบันทึกรูปแบบเพื่อให้คุณยังต้องการที่จะเพิ่มการตรวจสอบทั้งในระดับรุ่น (กว่า) หรือการตรวจสอบระดับรูปแบบในทั้งสองกรณีใน (resp.) รูปแบบหรือรูปแบบของclean()
วิธีการ
ดังนั้นเพื่อให้เรื่องสั้นสั้น:
และคุณควรจะโอเคสมมติว่า RDBMS ของคุณเคารพการตรวจสอบข้อ จำกัด ของหลักสูตร
ทราบเพียงว่ามีการออกแบบนี้ของคุณInspection
รูปแบบเป็นไร้ประโยชน์โดยสิ้นเชิงร้าย (ยังมีค่าใช้จ่าย!) - คุณจะได้รับคุณสมบัติเดียวกันแน่นอนด้วยต้นทุนที่ต่ำโดยการย้าย FKs (และข้อ จำกัด ของการตรวจสอบ ฯลฯ ) InspectionReport
โดยตรงใน
ขณะนี้อาจมีโซลูชันอื่น - รักษาโมเดลการตรวจสอบ แต่วาง FK เป็น OneToOneField บนส่วนอื่น ๆ ของความสัมพันธ์ (ในไซต์และกลุ่ม):
class Inspection(models.Model):
id = models.AutoField(primary_key=True) # a pk is always unique !
class InspectionReport(models.Model):
# you actually don't need to manually specify a PK field,
# Django will provide one for you if you don't
# id = models.AutoField(primary_key=True)
inspection = ForeignKey(Inspection, ...)
date = models.DateField(null=True) # you should have a default then
comment = models.CharField(max_length=255, blank=True default="")
signature = models.CharField(max_length=255, blank=True, default="")
class Group(models.Model):
inspection = models.OneToOneField(Inspection, null=True, blank=True)
class Site(models.Model):
inspection = models.OneToOneField(Inspection, null=True, blank=True)
yoursite.inspection.inspectionreport_set.all()
และจากนั้นคุณจะได้รับรายงานทั้งหมดสำหรับเว็บไซต์ที่กำหนดหรือกลุ่มที่มี
วิธีนี้หลีกเลี่ยงการเพิ่มข้อ จำกัด หรือการตรวจสอบความถูกต้องใด ๆ แต่ด้วยค่าใช้จ่ายของระดับการอ้อมเพิ่มเติม (SQL join
clause เป็นต้น)
โซลูชันใดที่จะ "ดีที่สุด" นั้นขึ้นอยู่กับบริบทดังนั้นคุณต้องเข้าใจความหมายของทั้งสองและตรวจสอบว่าคุณใช้แบบจำลองของคุณเพื่อหาว่าสิ่งใดเหมาะสมกว่าสำหรับความต้องการของคุณ เท่าที่ฉันกังวลและไม่มีบริบทเพิ่มเติม (หรือมีข้อสงสัย) ฉันควรใช้วิธีแก้ปัญหาที่มีระดับการอ้อมน้อยกว่า แต่ YMMV
หมายเหตุเกี่ยวกับความสัมพันธ์ทั่วไป: สิ่งเหล่านี้มีประโยชน์เมื่อคุณมีแบบจำลองที่เกี่ยวข้องและ / หรือไม่ทราบล่วงหน้าว่าแบบใดที่คุณต้องการเกี่ยวข้องกับตัวคุณเอง สิ่งนี้มีประโยชน์เป็นพิเศษสำหรับแอพที่ใช้ซ้ำได้ (คิดว่า "ความคิดเห็น" หรือคุณสมบัติ "แท็ก" ฯลฯ ) หรือสิ่งที่ขยายได้ (กรอบการจัดการเนื้อหาและอื่น ๆ ) ข้อเสียคือมันทำให้การสืบค้นหนักกว่ามาก (และค่อนข้างทำไม่ได้เมื่อคุณต้องการที่จะทำแบบสอบถามด้วยตนเองในฐานข้อมูลของคุณ) จากประสบการณ์พวกเขาสามารถกลายเป็น PITA bot wrt / code และ perfs ได้อย่างรวดเร็วดังนั้นควรเก็บไว้เมื่อไม่มีวิธีแก้ปัญหาที่ดีกว่า (และ / หรือเมื่อการบำรุงรักษาและค่าใช้จ่ายรันไทม์ไม่เป็นปัญหา)
2 เซนต์ของฉัน
Inspection
คลาสและจากนั้นซับคลาสลงในSiteInspection
และGroupInspection
สำหรับส่วนที่ไม่ใช่คอมมอน