Tym razem inne podejście, naturalne dziedziczenie abstrakcyjnych modeli z dwoma dodatkowymi metodami.

W przeciwieństwie do poprzedniego przykładu, pozwala używać super() w abstrakcyjnych klasach pośrednich.

from django.db import models

class AbstractMixin(object):
    _classcache = {}

    @classmethod
    def contribute(cls):
        return {}

    @classmethod
    def construct(cls, *args, **kwargs):
        attrs = cls.contribute(*args, **kwargs)
        attrs.update({
            '__module__': cls.__module__,
            'Meta': type('Meta', (), {'abstract': True}),
        })
        key = (args, tuple(kwargs.items()))
        if not key in cls._classcache:
            clsname = (('%s%x' % (cls.__name__, hash(key)))
                       .replace('-', '_'))
            cls._classcache[key] = type(clsname, (cls, ), attrs)
        return cls._classcache[key]

Przykład użycia:

class CategoryFactory(models.Model, AbstractMixin):
    name = models.CharField(max_length=100)

    class Meta:
        abstract = True

    def __unicode__(self):
        return self.name

class ProductFactory(models.Model, AbstractMixin):
    name = models.CharField(max_length=100)

    class Meta:
        abstract = True

    @classmethod
    def contribute(cls, category):
        return {'category': models.ForeignKey(category)}

    def __unicode__(self):
        return u'%s / %s' % (self.category, self.name)

Konkretyzacja klas:

class MyCategory(CategoryFactory.construct()):
    pass
 
class MyProduct(ProductFactory.construct(category=MyCategory)):
    pass

Działa również nasz test:

from . import models

c = models.MyCategory(name='cat')
p = models.MyProduct(name='prod', category=c)
print p # 'cat / prod'