- July 3, 2010
- models child-model multi-table-inheritance polymorphy
- 1 (after 1 ratings)
A common problem (it hit the Django mailinglist a couple of times) is that if you get
models.Topping.objects.all(), you get a list of toppings, although they stand for other classes such as
CheeseTopping. If you need the actual object, just derive
PolymorphicModel, and say
topping.actual_instance. This will give you e.g. a
Sometimes you just want to check for the actual class. You can get it by saying
There is a slight performance impact when creating objects because they have to be saved twice.
NEWS: A good alternative to this approach is the InheritanceManager.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
class PolymorphicModel(models.Model): u"""Abstract model class, which provides the attribute ``actual_instance``. This solves the problem that Django's ORM does not implement automatic resolution of polymorphy. For example, if you get a list of Toppings, they're just Toppings. However sometimes, you must have the actual object, i.e. CheeseTopping, SalamiTopping etc. Then, ``topping.actual_instance`` will give just that. Simply derive the top-level model class from this one, and then you can easily resolve polymorphy in it and its derived classes. """ content_type = models.ForeignKey(ContentType, null=True, blank=True) actual_object_id = models.PositiveIntegerField(null=True, blank=True) actual_instance = generic.GenericForeignKey("content_type", "actual_object_id") def save(self, *args, **kwargs): u"""Saves the instance and assures that `actual_instance` is set. """ super(PolymorphicModel, self).save(*args, **kwargs) if not self.actual_object_id: self.actual_instance = self super(PolymorphicModel, self).save() class Meta: abstract = True