Django models: different methods on each instance? Imagine I have code like this in (it's about the concept; this is example code):

# models.py
from django.db import models

class Monster(models.Model):
    x = models.FloatField()
    y = models.FloatField()
    def use_unique_ability(self, target):
        ''' different monsters types will implement this differently '''
    def check_attack(self, player): # should I attack this player?
        ''' different monsters types will implement this differently '''
    class Meta:
        abstract = True

class SlimyMonster(Monster):
    def __init__(self):
        self.attack = 3
        self.hit_points = 10
    def use_unique_ability(self, target):
        target.hit_points -= 2 * target.attack
    def check_attack(self, player): # should I attack this player?
        return player.hit_points &lt; self.hit_points

class CaerbannogRabbit(Monster):
    ''' well, you get the idea '''

# many more monsters


Each monster has the same attributes and method names, but different values and implementation. Monster would probably be an interface in Java. Each monster type will override only some of the many methods.

This technically works, but it has some significant downsides:


Each monster is a new database table with the same columns
Because of that, I need a lot of queries to check for all monsters
I need GenericForeignKey to reference individual monsters (instances of any of the model classes)


The other extreme isn't exactly pretty either. This is based on dynamically mixin a base class to an instance (+this) and how to import a module given the full path?:

# models.py
from django.db import models
from os.path import join
from inspect import isclass
from imp import load_source
from settings import PATH_TO_MONSTER_FILES

class InconsistentMonsterError(Exception): pass

class MonsterClass(models.Model):
    name = models.CharField(max_length = 32)
    attack = models.PositiveIntegerField(default = 1)
    defense = models.PositiveIntegerField(default = 10)
    method_file = models.CharField(max_length = 128) # it's a source file, not media file, so I'm using CharField
    def __init__(self, *args, **kwargs):
        super(MonsterClass, self).__init__(*args, **kwargs)
        try:
            modul = load_source(self.method_file, join(PATH_TO_MONSTER_FILES, self.method_file))
        except IOError:
            raise InconsistentMonsterError('no file named %s' % join(PATH_TO_MONSTER_FILES, self.method_file))
        classes = [cls for cls in [getattr(modul, x) for x in dir(modul)] if isclass(cls)]
        if not len(classes):
            raise InconsistentMonsterError('file %s doesn\'t contain classes' % join(PATH_TO_MONSTER_FILES, self.method_file))
        bases = self.__class__.__bases__ + (classes[-1], )
        self.__class__ = type('NewClassName', bases, {
            '__module__': MonsterClass.__module__,
        })

class MonsterInstance(models.Model):
    cls = models.ForeignKey(MonsterClass)
    x = models.FloatField()
    y = models.FloatField()


and for each monster a file like this:

# slimy_monster.py
class SlimyMonster(): # not a Model
    def use_unique_ability(self, target):
        ''' different monsters types will implement this differently '''
    def check_attack(self, player): # should I attack this player?
        ''' different monsters types will implement this differently '''



The code seems... inellegant. It's complex, and it's like using eval (execute code based on an 'external' string)
Every monster must be changed in two places: the database and a file (although I suppose I could define database values in the file)


Given these two options, should I use one of them, or something in between? I tend towards the second option, but I'm not quite satisfied.
What you want is inheritance as a proxy model.

In your subclasses, use the following Meta option:

class SlimyMonster(Monster):
    class Meta:
        proxy = True

    def some_method_to_override(self):
        ...


This way the subclassing has no effect on the database side, only on the Python side.