Django模型如何与多个模型建立关联

6
假设有一个抽象模型CarOwner:一个人或企业可以成为CarOwner。此外,具有特定VIN的汽车可以属于(关联)个人或企业中的任何一个,但不能同时属于两者(互斥情况)。在以下代码的最后,我提出了两种可能性(请参见代码中的注释“#1。我应该拥有这个吗?”和“#2. ...还是应该有这个? “)。在第一种情况下,建立了与抽象模型的多对一关系,我不确定这是否是正确的方式。在第二种情况下,建立了两个关系,我也不确定这是否正确,特别是不清楚如何使它们相互排斥。那么哪一个是正确的,如果两者都不正确,请提供正确答案。谢谢。
class CarOwner(models.Model):
    location = models.CharField(max_length=50, blank=True)

    class Meta:
        abstract = True

class Person(CarOwner):
    name = models.CharField(max_length=50, blank=True)

class Business(CarOwner):
    business_id = models.CharField(max_length=50, blank=True)

class Car(models.Model):
    vin = models.CharField(max_length=50, blank=True)

    # 1. SHOULD I HAVE THIS??? (CarOwner is abstract)
    carowner = models.ForeignKey(CarOwner, blank=True, null=True)

    # 2. ...OR SHOULD I HAVE THIS???
    person = models.ForeignKey(Person, blank=True, null=True)
    business = models.ForeignKey(Business, blank=True, null=True)
2个回答

9

像jproffitt提到的,通用关系可能是您的一个好解决方案。另外,您可以使用#2,并通过创建属性并添加一些简单逻辑使其更加便捷:

class Car(models.Model):
    vin = models.CharField(max_length=50, blank=True)
    person = models.ForeignKey(Person, blank=True, null=True)
    business = models.ForeignKey(Business, blank=True, null=True)

    @property
    def carowner(self):
        return self.person or self.business

    @carowner.setter
    def carowner(self, obj):
        if type(obj) == Person:
            self.person = obj
            self.business = None
        elif type(obj) == Business:
            self.business = obj
            self.person = None
        else:
            raise ValueError("obj parameter must be an object of Business or Person class")

但是如果要查询,你必须使用 个人公司


谢谢。那么,在同一模型中使用两个ForeignKey实际上是被允许的吗?根据我以前对Django文档网站的探索,我曾经理解它仅允许在某些多对多关系的情况下使用。 - jazzblue
当然是的,我不确定Django文档的哪一部分会提出其他建议。 - zaan

4

由于CarOwner是抽象的,您无法执行#1操作。您可以使CarOwner具体化(数据库表继承),然后该操作将起作用,但表继承会带来自己的一套复杂性。您可以执行#2或使用通用外键:

carowner_content_type = models.ForeignKey(ContentType)
carowner_object_id = models.PositiveIntegerField()
carowner = generic.GenericForeignKey('carowner_content_type', 'carowner_object_id')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接