julx
julx

Reputation: 9091

Django polymorphism hack

I'm trying to bake out a sort of "single table inheritence" a.k.a. "table per hierarchy" model in Django.

Here's what I'd like to do:

class PolymorphicModel(models.Model):

   content_type = models.ForeignKey(ContentType)

   class Meta:
       abstract = True

   def __init__(self, *args, **kwargs):
       super(PolymorphicModel, self).__init__(*args, **kwargs)
       # Dynamically switch the class to the actual one
       self.__class__ = self.content_type.model_class()

   def save(self, *args, **kwargs):
       if not self.content_type:
           # Save the actual class name for the future.
           self.content_type = ContentType.objects.get_for_model(self.__class__)
           super(PolymorphicModel, self).save(*args, **kwargs)

And then the actual hierarchy:

class Base(PolymorphicModel):

    a = models.IntegerField()
    b = models.IntegerField()

    @abstractmethod
    def something(self): pass


class DerivedA(Base):

    def something(self):
        return self.a


class DerivedB(Base):

    def something(self):
        return self.b

Unfortunately I get an error DoesNotExist when constructing DerivedA(). It complains about content_type not existing.

EDIT:

Concerning my questions:

See my answer below: content_type is apparently not a viable name.

Yes it is! And it works beautifully. Using class names instead of content type is also possible. This has an added value of handling proxy = True appropriately.

Upvotes: 0

Views: 333

Answers (1)

julx
julx

Reputation: 9091

Ups, well apparently content_type is a reserved name. I changed the property name to ct and it works now.

I've published by solution here: http://djangosnippets.org/snippets/2408/

Upvotes: 1

Related Questions