Yorumlarda belirtildiği gibi, "bu kurulumla her ikisine de ihtiyaç duyması" nın sebebi sadece blank=True
FK alanlarınızı eklemeyi unutmanızdır , böylece ModelForm
(özel alan veya yönetici tarafından oluşturulan varsayılan) form alanını zorunlu hale getirecektir . Db şema düzeyinde, bu FK'lardan birini veya hiçbirini doldurabilirsiniz, çünkü bu db alanlarını nulllable ( null=True
argüman ile) yaptığınızdan, tamam olur .
Ayrıca, (diğer yorumlarım varsa), FK'larınızın gerçekten benzersiz olmasını istediğinizi kontrol etmek isteyebilirsiniz. Bu, teknik olarak bir çok ilişkinizi bire bir ilişkiye dönüştürür - belirli bir GroupID veya SiteId için yalnızca bir tek 'inceleme' kaydına izin verilir (bir GroupId veya SiteId için iki veya daha fazla 'denetiminiz olamaz). . GERÇEKTEN istediğiniz bu ise, bunun yerine açık bir OneToOneField kullanmak isteyebilirsiniz (db şeması aynı olacaktır ancak model daha açık ve ilgili tanımlayıcı bu kullanım durumu için çok daha kullanışlı olacaktır).
Bir yan not olarak: Django Modelinde, bir ForeignKey alanı ham kimlik olarak değil ilgili bir model örneği olarak gerçekleşir. IOW, bu verilen:
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)
sonra bar.foo
çözülecek foo
, değil foo.id
. Bu yüzden kesinlikle InspectionID
ve SiteID
alanlarınızı uygun inspection
ve olarak yeniden adlandırmak istiyorsunuz site
. BTW, Python'da, adlandırma kuralı, sınıf adları ve sözde sabitler dışında herhangi bir şey için 'all_lower_with_underscores' şeklindedir.
Şimdi temel sorunuz için: veritabanı düzeyinde "biri veya diğeri" kısıtlamasını zorlamanın standart bir SQL yolu yoktur, bu nedenle genellikle Django modelinde modelin meta "kısıtlamaları" ile yapılan bir CHECK kısıtlaması kullanılarak yapılır. seçeneğini seçin .
Bununla birlikte, db düzeyinde kısıtlamaların gerçekte nasıl desteklendiği ve uygulandığı DB satıcınıza bağlıdır (MySQL <8.0.16 sadece bunları görmezden gelin ) ve burada ihtiyacınız olacak kısıtlama türü formda uygulanmayacaktır. veya model seviyesi doğrulama , çok, modeli kurtarmaya çalışırken yalnızca ayrıca en ya doğrulama eklemek istediğiniz modeli düzeyinde (sırasıyla.) modeli veya formun her iki durumda da (tercihen) veya form düzeyi doğrulama clean()
yöntemiyle.
Uzun bir hikaye kısaca anlatmak gerekirse:
ve RDBMS'nizin elbette kontrol kısıtlamalarına saygı duyduğunu varsayarak iyi olmalısınız.
Bu tasarımla, Inspection
modelinizin tamamen işe yaramaz (ancak maliyetli!) Bir dolaylı olduğunu unutmayın - FK'leri (ve kısıtlamaları, doğrulama vb.) Doğrudan içine taşıyarak aynı özellikleri daha düşük bir maliyetle elde edersiniz InspectionReport
.
Şimdi başka bir çözüm olabilir - Denetim modelini koruyun, ancak FK'yi ilişkinin diğer ucuna (Site ve Grup'ta) OneToOneField olarak koyun:
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)
Ardından, belirli bir Site veya Grup için tüm raporları ile alabilirsiniz yoursite.inspection.inspectionreport_set.all()
.
Bu, herhangi bir özel kısıtlama veya doğrulama eklemek zorunda kalmamakta, ancak ek bir dolaylama düzeyi (SQL join
yantümcesi vb.) Pahasına olmaktadır.
Bu çözümlerden hangisinin "en iyi" olacağı gerçekten bağlama bağlıdır, bu nedenle her ikisinin de sonuçlarını anlamanız ve hangilerinin kendi ihtiyaçlarınıza daha uygun olduğunu bulmak için modellerinizi nasıl kullandığınızı kontrol etmeniz gerekir. Endişe duyduğum kadarıyla ve daha fazla bağlam (veya şüphesiz) olmadan, çözümü daha az dolaylı seviyelerle, ancak YMMV ile kullanmayı tercih ederim.
Genel ilişkilerle ilgili not: olası pek çok ilgili modeliniz olduğunda ve / veya kendinizle hangi modelleri ilişkilendirmek isteyeceğinizi bilmiyorsanız bunlar kullanışlı olabilir. Bu, yeniden kullanılabilir uygulamalar ("yorumlar" veya "etiketler" vb özelliklerini düşünün) veya genişletilebilir uygulamalar (içerik yönetimi çerçeveleri vb.) İçin özellikle yararlıdır. Dezavantajı, sorgulamayı çok daha ağır hale getirir (ve db'nizde manuel sorgular yapmak istediğinizde pratik değildir). Deneyimden, hızlı bir şekilde bir PITA bot wrt / kodu ve perfs olabilirler, bu yüzden daha iyi bir çözüm olmadığında (ve / veya bakım ve çalışma zamanı yükü bir sorun olmadığında) tutmak daha iyidir.
Benim 2 sentim.
Inspection
sınıfını ve sonra içine alt sınıfSiteInspection
veGroupInspection
için sigara -ortak parçaları.