Frage

Suppose there is an abstract model CarOwner: whereas a Person or a Business can be a CarOwner. In addition a Car with a certain VIN can belong (relate) to either a Person or a Business, but not both (mutually exclusive case). At the very end of the following code I presented two possibilities (see comments in the code "# 1. SHOULD I HAVE THIS???" and "# 2. ...OR SHOULD I HAVE THIS???"). In the first possibility a Many-to-One relationship is established to an abstract model and I am not sure if this is the right way. In the second case two relationships are established and I am not sure if that is correct either, especially it is not clear how to make them mutually exclusive. So which one is right and if neither, please, provide the right answer if you could. Thanks.

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)
War es hilfreich?

Lösung

Like jproffitt mentioned, generic relations might be a good solution for you. Alternatively you can use #2 and make it a bit more convenient by creating property and adding some simple logic to it:

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

However for queries you'll have to use person or business.

Andere Tipps

Since CarOwner is abstract, you cannot do #1. You could make CarOwner concrete (db table inheritance), and then that would work, but table inheritance brings its own set of complications. You could either do #2 or use a generic foreign key:

carowner_content_type = models.ForeignKey(ContentType)
carowner_object_id = models.PositiveIntegerField()
carowner = generic.GenericForeignKey('carowner_content_type', 'carowner_object_id')
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top