# just a demo example
# the actual code is at http://gist.github.com/608595

from django.db import models
from polymorphic import polymorphic_manager


class Player(models.Model):
    hitpoints = models.PositiveIntegerField(default=100)

    # polymorphic_on field
    race = models.SmallIntegerField(choices=enumerate(['Elf', 'Troll', 'Human']))

    # keep the default (non-polymorphic) manager
    objects = models.Manager()

    # a new manager polymorphic on Player.race
    objects_by_race = polymorphic_manager(on=race)

    def __unicode__(self):
        return u'Player(%s)' % self.pk


class Elf(Player):
    bows = models.PositiveIntegerField(default=0)

    # polymorphic manager for race=0
    objects = Player.objects_by_race.polymorphic_identity(0)

    def __unicode__(self):
        return u'Elf(%s)' % self.pk


class Troll(Player):
    axes = models.PositiveIntegerField(default=0)

    # polymorphic manager for race=1
    objects = Player.objects_by_race.polymorphic_identity(1)

    def __unicode__(self):
        return u'Troll(%s)' % self.pk


class Human(Player):

    # polymorphic manager for race=2
    objects = Player.objects_by_race.polymorphic_identity(2)

    class Meta:
        proxy = True

    def __unicode__(self):
        return u'Human(%s)' % self.pk


def test():
    from random import choice
    Player.objects.all().delete()

    # create a bunch of random type players
    for i in xrange(10):
        choice([Elf, Troll, Human]).objects.create()

    # retrieval through the polymorphic manager returns instances of the right class
    print "Automatically downcast players:", Player.objects_by_race.all()

    # retrieval through default Player manager returns Player instances as usual
    players = Player.objects.all()
    print "Non-downcast players:", players

    # but they can be explicitly downcast to the right class
    print "Explicitly downcast players:", map(Player.objects_by_race.downcast, players)

    # retrieving the instances of a specific class works as expected
    print "Elfs:", Elf.objects.all()
    print "Trolls:", Troll.objects.all()
    print "Humans:", Human.objects.all()

test()