의견에서 언급했듯이 "이 설정으로 둘 다 필요하다"는 이유는 blank=True
FK 필드에 를 추가하는 것을 잊었 기 때문입니다.ModelForm
입니다. . db 스키마 레벨에서, FK 중 하나 또는 모두를 채울 수 있습니다 null=True
. 인수를 사용하여 해당 db 필드를 널 입력 가능하게 만들었으므로 괜찮습니다 .
또한 (내 다른 의견 참조), 당신은 당신이 정말로 FK를 독창적으로 만들고 싶어하는지 확인할 수 있습니다. 이는 기술적으로 일대 다 관계를 일대일 관계로 전환합니다. 주어진 GroupID 또는 SiteId에 대해 하나의 '검사'레코드 만 허용됩니다 (하나의 GroupId 또는 SiteId에 대해 둘 이상의 '검사'를 가질 수 없음) . 이것이 정말로 원하는 경우 대신 명시 적 OneToOneField를 사용하는 것이 좋습니다 (db 스키마는 동일하지만 모델은 더 명확하고 관련 설명자는이 사용 사례에 훨씬 더 유용합니다).
참고로 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 방법이 없으므로 일반적으로 CHECK 제약 조건을 사용하여 수행 됩니다. CHECK 제약 조건 은 모델의 메타 "제약"을 사용 하여 Django 모델에서 수행됩니다. 옵션 .
즉, DB 수준에서 제약 조건이 실제로 지원되고 적용되는 방식은 DB 공급 업체에 따라 다르며 (예 : MySQL <8.0.16 그냥 무시 하십시오) 여기에서 필요한 제약 종류 는 양식에 적용되지 않습니다 모델 수준의 검증 , 당신은, 그래서 모델을 저장하려고하는 경우에만 또한 상기 중 유효성 검사를 추가 할 모델 수준 (RESP.) 모델 또는 양식의 두 경우에 (바람직) 또는 양식 수준의 검증 clean()
방법.
긴 이야기를 짧게하려면 :
unique=True
먼저이 제약 조건 이 정말로 필요한지 다시 확인하고, 그렇다면 FK 필드를 OneToOneField로 바꾸십시오.
blank=True
FK (또는 OneToOne) 필드에 인수를 추가하십시오.
- 모델의 메타에 적절한 검사 제약 조건 을 추가하십시오 . 문서는 간결하지만 ORM을 사용하여 복잡한 쿼리를 수행하는 것으로 알고 있다면 충분히 명시 적입니다.
clean()
하나 또는 다른 필드가 있는지 확인하고 유효성 검사 오류가 발생 하는 방법을 모델에 추가하십시오.
RDBMS가 검사 제한 조건을 존중한다고 가정하면 괜찮을 것입니다.
이 디자인을 사용하면 Inspection
모델이 완전히 쓸모가 없지만 (비용이 많이 드는!) 간접적입니다. FK (및 제약 조건, 유효성 검사 등)를로 직접 이동하여 더 적은 비용으로 동일한 기능을 정확하게 얻을 수 있습니다 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
절 등)이 필요합니다.
어떤 솔루션이 "최상의"솔루션인지는 상황에 따라 달라 지므로 두 가지의 의미를 이해하고 일반적으로 모델을 사용하여 자신의 요구에 더 적합한 방법을 찾는 방법을 확인해야합니다. 내가 우려하고 더 많은 맥락 (또는 의심스런)이없는 한, 간접 수준은 적지 않지만 YMMV와 함께 솔루션을 사용하고 싶습니다.
일반적인 관계에 관한 NB : 실제로 가능한 많은 관련 모델이 있거나 어떤 모델이 자신과 관련이 있는지 미리 알지 못할 때 편리합니다. 이것은 재사용 가능한 앱 ( "코멘트"또는 "태그"등의 기능을 생각 함) 또는 확장 가능한 앱 (콘텐츠 관리 프레임 워크 등)에 특히 유용합니다. 단점은 쿼리가 훨씬 무겁다는 것입니다 (DB에서 수동 쿼리를 수행하려는 경우 오히려 비실용적입니다). 경험을 통해 PITA 봇 wrt / 코드 및 성능이 빠르게 향상 될 수 있으므로 더 나은 솔루션이없는 경우 (및 / 또는 유지 관리 및 런타임 오버 헤드가 문제가되지 않는 경우) 유지하는 것이 좋습니다.
내 2 센트
Inspection
클래스를, 다음으로 서브 클래스SiteInspection
및GroupInspection
에 대한 비 -common 부품.