title: Django inheritance and polymorphism with proxy models
body: <p>I'm working on a Django project that I did not start and I am facing a problem of <strong>inheritance</strong>.<br>
  I have a big model (simplified in the example) called <code>MyModel</code> that is supposed to represents different kind of items.</p>
  
  <p>All the instance objects of <code>MyModel</code> should have the same fields but the methods behaviours varies a lot depending on the item type.</p>
  
  <p>Up to this moment this has been designed using a single <code>MyModel</code> field called <code>item_type</code>.<br>
  Then methods defined in MyModel check for this field and perform different logic using multiple if:</p>
  
  <pre><code>def example_method(self):
      if self.item_type == TYPE_A:
          do_this()
      if self.item_type == TYPE_B1:
          do_that()
  </code></pre>
  
  <p>Even more, some of the sub-types have many things in common, so let's say the subtypes <code>B</code> and <code>C</code> represents a 1st level of inheritance.
  Then these types have sub-types being for example <code>B1</code>, <code>B2</code>, <code>C1</code>, <code>C2</code> (better explained in the example code below). </p>
  
  <p>I would say that's not the best approach to perform polymorphism.</p>
  
  <p>Now I want to change these models to use real inheritance.  </p>
  
  <p>Since all submodels have the same fields I think multi-table inheritance is not necessary. I was thinking to use <strong>proxy models</strong> because only their behaviour should change depending on their types.</p>
  
  <p>This a pseudo-solution I came up to: </p>
  
  <pre><code>ITEM_TYPE_CHOICES = (
      (TYPE_A, _('Type A')),
      (TYPE_B1, _('Type B1')),
      (TYPE_B2, _('Type B2')),
      (TYPE_C1, _('Type C1')),
      (TYPE_C2, _('Type C2')))
  
  
  class MyModel(models.Model):
      item_type = models.CharField(max_length=12, choices=ITEM_TYPE_CHOICES)
  
      def common_thing(self):
          pass
  
      def do_something(self):
          pass
  
  
  class ModelA(MyModel):
      class Meta:
          proxy = True
  
      def __init__(self, *args, **kwargs):
          super().__init__(self, *args, **kwargs)
          self.item_type = TYPE_A
  
      def do_something(self):
          return 'Hola'
  
  
  class ModelB(MyModel):
      class Meta:
          proxy = True
  
      def common_thing(self):
          pass
  
  class ModelB1(ModelB):
      class Meta:
          proxy = True
  
      def __init__(self, *args, **kwargs):
          super().__init__(self, *args, **kwargs)
          self.item_type = TYPE_B1
  
      def do_something(self):
          pass
  
  
  class ModelB2(ModelB):
      class Meta:
          proxy = True
  
      def __init__(self, *args, **kwargs):
          super().__init__(self, *args, **kwargs)
          self.item_type = TYPE_B2
  
      def do_something(self):
          pass
  </code></pre>
  
  <p>This might work if we already know the type of the object we are working on.<br>
  Let's say we want to instantiate a MyModel object of type C1 then we could simply instantiate a <code>ModelC1</code> and the item_type would be set up correctly.</p>
  
  <p>The problem is how to get the correct proxy model from the generic MyModel instances?</p>
  
  <p>The most common case is when we get a queryset result: <code>MyModel.objects.all()</code>, all these objects are instances of MyModel and they don't know anything about the proxies.</p>
  
  <p>I've seen around different solution like  <a href="https://django-polymorphic.readthedocs.io/" rel="noreferrer">django-polymorphic</a> but as I've understood that relies on multi-table inheritance, isn't it?  </p>
  
  <p>Several SO answers and custom solutions I've seen:</p>
  
  <ul>
  <li><a href="https://stackoverflow.com/a/7526676/1191416">https://stackoverflow.com/a/7526676/1191416</a></li>
  <li><a href="https://stackoverflow.com/questions/1397537/polymorphism-in-django">Polymorphism in Django</a></li>
  <li><a href="http://anthony-tresontani.github.io/Python/2012/09/11/django-polymorphism/" rel="noreferrer">http://anthony-tresontani.github.io/Python/2012/09/11/django-polymorphism/</a></li>
  <li><a href="https://github.com/craigds/django-typed-models" rel="noreferrer">https://github.com/craigds/django-typed-models</a></li>
  <li><a href="https://stackoverflow.com/questions/18473850/creating-instances-of-django-proxy-models-from-their-base-class">Creating instances of Django proxy models from their base class</a></li>
  </ul>
  
  <p>but none of them convinced me 100%..</p>
  
  <p>Considering this might be a common scenario did anyone came up with a better solution?</p>