Django模型与多个模型的关系

时间:2014-01-04 20:58:40

标签: django django-models foreign-key-relationship many-to-one django-orm

假设有一个抽象模型CarOwner:而Person或Business可以是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 个答案:

答案 0 :(得分:8)

与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")

但是对于查询,您必须使用 person business

答案 1 :(得分:3)

由于CarOwner是抽象的,所以你不能做#1。您可以使CarOwner具体(db表继承),然后这将起作用,但表继承带来了自己的一系列复杂性。你可以做#2或使用通用外键:

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