1

My aim is to access an attribute of a subclass without knowing beforehand which of the two subclasses was choosen (multiple choice classes)

Ideally there is an attribute in the SuperClass that changes depending upon which SubClass was choosen.

The reason is that I have created Forms directly from the SubClasses and use the SuperClass as the entry point for accessing values.

I am aware I can use true or false with hasattr(horse), but ideally I am asking if there is a bit neater solution, such as the SubClass can signal to SuperClass which SubClass was used.

e.g. for product 8 on my list

subclass = getattr(Product(8), 'subclass', 0)
print(subclass)
>> Horse

or

place = Product.location
Print(place)
>> Stable

The whole "problem" stem from the fact that I create Products via SubClass Forms, meanwhile much of the later logic goes top-down, starting with Product

class Product(models.Model):
  product_name = models.Charfield(max_length=20)

class Car(Product):
  engine = models.Charfield(max_length=20)
  location = models.Charfield(default="Garage", max_length=20, editable=False)
  product = models.OneToOneField(Product, parent_link=True, on_delete=models.CASCADE)

class Horse(Product):
  saddle_model = models.Charfield(max_length=20)
  location = models.Charfield(default="Stable", max_length=20, editable=False)
  product = models.OneToOneField(Product, parent_link=True, on_delete=models.CASCADE)
Jaco
  • 1,564
  • 2
  • 9
  • 33

1 Answers1

1

If you want to access the other models properties from the Product model you could implement a property method on Product that inspects the reverse relation between it and its related models and then returns the appropriate location (https://docs.djangoproject.com/en/2.1/topics/db/examples/one_to_one/).

class Product(models.Model):
    product_name = models.CharField(max_length=20)

    @property
    def location(self):
        """Return the location of the related subclass"""
        if self.car:
            return self.car.location
        elif self.horse:
            return self.horse.location
        else:
            return None

    @property
    def product_subclass(self):
        """Return the location of the related subclass"""
        if self.car:
            return self.car
        elif self.horse:
            return self.horse
        else:
            return None

This should allow you to use it like so:

car_product = Product.objects.create(product_name="Car Product")
car = Car.objects.create(engine="engine", location="123 Fake Street", product=car_product)
print(car_product.location)  # Prints "123 Fake Street"

horse_product = Product.objects.create(product_name="Horse Product")
horse = Horse.objects.create(saddle_model="Buckingham", location="1982 Old Street", product=horse_product)
print(horse_product.location)  # Prints "1982 Old Street"

If you'd like to do something similar to return the subclass:

print(car_product.product_subclass)  # Prints <Car object>
print(horse_product.product_subclass)  # Prints <Horse object>

These property methods require a database query to check with the Car and Horse table's, since the relation is stored on those tables as the product_id column. So to figure out if product.car is valid, the ORM does a query similar to Car.objects.get(product_id=product.pk)

A. J. Parr
  • 7,731
  • 2
  • 31
  • 46
  • Thanks, I can see if I would use def __str__(self): return self.location below a subclass will return a clean variable when asking for it, such as horse_product.location >> stable – Jaco Dec 12 '18 at 03:58
  • Since location is a `CharField` it should always return a clean variable like you mentioned without the need to override `__str__()`; i.e. print(horse.location) -> "Stable" or print(horse_product.location) -> "Stable". I prefer to have the `__str__()` method of an instance to return a human readable and meaningful definition of the object, i.e. `__str__(self): return f"{self.__class__.__name__} #{self.pk} at {self.location}"` Which would return "Product #1 at Stable" or "Horse #2 at Stable", but this is personal preference. It shouldn't affect the logic of your program, just presentation. – A. J. Parr Dec 12 '18 at 04:43