0

I have a classic use case for Django multi-table model inheritance, in an app that manages remote hosts.

The app can work with generic "RemoteHost", or "SshHost" (that is also a RemoteHost), or "EsxiHost" (that is also a SshHost), so naturally I went for multi-table model inheritance:

class RemoteHost(models.Model):
    ...
    def shutdown(self):
        raise NotImplemented()

class SshHost(RemoteHost):
    ...
    def shutdown(self):
        # run SSH shutdown command

class EsxiHost(SshHost):
    ...
    def shutdown(self):
        # shutdown running virtual machine using VMware API
        SshHost(self).shutdown()

I want to be able to "shutdown" managed hosts without knowing the specific host type, e.g. RemoteHost.objects.get(pk=1).shutdown(), but it turns out that Django data model will return the explicitly requested type (per my experience, as well as the docs).

I am looking for a clean way to obtain the most specialized instance available based on a base-class queryset.

So far, the "cleanest" approach I came up with looks something like this:

class RemoteHost(models.Model):
    ...
    def get_specialized_instance(self):
        try:
            return self.sshhost.get_specialized_instance()
        except self.DoesNotExist:
            return self

class SshHost(RemoteHost):
    ...
    def get_specialized_instance(self):
        try:
            return self.esxihost.get_specialized_instance()
        except self.DoesNotExist:
            return self

class EsxiHost(SshHost):
    ...
    def get_specialized_instance(self):
        return self

The upside of this approach is that it works :-)

But I don't like it for the following reasons:

  1. It requires the using code the explicitly call get_specialized_instance() on objects.
  2. It requires that the base models know about the models that extend them.

So, any advice on a better / cleaner way to achieve this will be welcome!

Itamar
  • 1,089
  • 1
  • 10
  • 18
  • see `related` section to the right, aswer it seems is right there: http://stackoverflow.com/questions/349206/how-do-i-find-the-concrete-class-of-a-django-model-baseclass?rq=1 – alko Oct 25 '13 at 08:51
  • 1
    [Django Polymorphic](https://github.com/chrisglass/django_polymorphic) could be your friend here, instead of writing your own ObjectManagers and setting ContentTypes, it does all the heavy lifting for you. – professorDante Oct 25 '13 at 17:39
  • @professorDante: Thanks! That's what I was looking for! Just need to keep in mind that it inflicts DB overhead... Semi-meta - why did you answer this as a comment instead of an answer? I can't flag it as "answer" this way... – Itamar Oct 26 '13 at 07:11
  • Updated to give it as an answer! It's not too onerous to do it yourself btw - I'm using [this](https://djangosnippets.org/snippets/1034/) snippet for one of my projects. – professorDante Oct 26 '13 at 17:50

1 Answers1

1

Django Polymorphic could be your friend here, instead of writing your own ObjectManagers and setting ContentTypes, it does all the heavy lifting for you. There you go, a proper answer! :-)

Itamar
  • 1,089
  • 1
  • 10
  • 18
professorDante
  • 2,290
  • 16
  • 26