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'