Inherit from non-abstract model without multi-table inheritance

1.4k Views Asked by At

Is there a way to inherit from an existing model in order to copy of all its fields (in a DRY manner) without invoking multitable inheritance if the model isn't abstract?

To be clear, I have a model Post, and I'd like to have another model GhostPost that mirrors Post exactly in terms of the available fields, but I do not want it to have multitable inheritance or any kind of relationship with Post. The problem is, Post isn't an abstract model, so Django will initiate multitable inheritance. Is there a way around this?

Update: What I'm looking for here is not a Python-level duplicate of the model, but an actual separate database table that mirrors those fields.

Solution: I followed @Brandon's advice and used an abstract model.

2

There are 2 best solutions below

5
On BEST ANSWER

You need to use a Proxy model in this case. It will allow you to extend a model that is not abstract but without mutli-table inheritance: https://docs.djangoproject.com/en/1.6/topics/db/models/#proxy-models

A proxy model will keep a single-table, so if you need one table for each model, I would suggest making a common abstract class to inherit from for the Post and GhostPost models.

0
On

You can add an extra BooleanField is_ghost, and override the default managers on both the original model and the proxy model:

class PostManager(models.Manager):
    def get_querset(self):
        return super(PostManager, self).get_queryset().filter(is_ghost=False)

class Post(models.Model):
    ...
    is_ghost = models.BooleanField(blank=True, default=False)
    objects = PostManager()

class GhostPostManager(models.Manager):
    def get_queryset(self):
        return super(GhostPostManager, self).get_queryset().filter(is_ghost=True)

class GhostPost(Post):
    objects = GhostPostManager()

    Meta:
        proxy = True

This will keep everything in a single table, but the managers and querysets will act like they were two separate models/tables.

The other solution is to use an abstract base class for both models. If you don't change the class name of your original Post model, and inherit from e.g. AbstractPost, I don't think this should cause any problems.