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:
- It requires the using code the explicitly call
get_specialized_instance()
on objects. - 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!