我已经定义了一些看起来像这样的模型:
class ABClass(models.Model):
#common attributes
class Meta:
abstract = True
class ConcreteClass1(ABClass):
#implementation specific attributes
class ConcreteClass2(ABClass):
#implementation specific attributes
class ModifiedConcreteClass1(ConcreteClass1):
#implementation specific attributes
我有一个视图,它带有一个'type'参数,指定要显示的类的类型。如果'type = None',我想显示ABClass的所有后代(在本例中为ConcreteClass {1,2},ModifiedConcreteClass1)。我在文档中搜索过,似乎找不到这样做的方法,不需要维护ConcreteClasses列表。 ABClass.__subclasses__()
似乎很有希望但是当我打电话时它会返回一个空列表。
目前我最好的策略是在models.py中创建一个CLASS_LIST变量,该变量在运行时使用inspect
方法填充ABClass的所有后代。有没有办法使用django api做到这一点?
由于
答案 0 :(得分:6)
如果'django.contrib.contenttypes'
中有INSTALLED_APPS
,则已维护ConcreteClasses列表。
我是这样做的:
class GetSubclassesMixin(object):
@classmethod
def get_subclasses(cls):
content_types = ContentType.objects.filter(app_label=cls._meta.app_label)
models = [ct.model_class() for ct in content_types]
return [model for model in models
if (model is not None and
issubclass(model, cls) and
model is not cls)]
class ABClass(GetSubclassesMixin, models.Model):
pass
当您需要子类列表时,只需调用ABClass.get_subclasses()
。
我在具体的基类中使用它,但我认为没有理由不使用抽象的类。
即使您的具体子类位于不同的Django应用程序中,此方法仍然有效。但请注意,它们与基类具有相同的app_label
,因此get_subclasses()
中的代码可以找到它们。
答案 1 :(得分:5)
我没有看到当你在后端设置抽象True时Django做了什么,但我玩了这个,我发现这有效。请注意,它仅适用于Python 2.6
from abc import ABCMeta
class ABClass():
__metaclass__ = ABCMeta
class ConcreteClass1(ABClass):
pass
class ConcreteClass2(ABClass):
pass
print ABClass.__subclasses__()
结果
[<class '__main__.ConcreteClass1'>, <class '__main__.ConcreteClass2'>]
如果不使用ABCMeta和__metaclass__
,您将收到一个空列表。
您可以阅读有关here内容的详细说明。只有这个问题,我不确定它是否会影响你是我无法弄清楚为什么当我创建一个ABClass的实例时,它找不到子类。也许通过玩一下并阅读更多的文档,它可能会让你在某个地方。
让我知道这对你有什么用,因为我对真正的答案真的很好奇。
答案 2 :(得分:5)
看看这个类似的问题:
我的解决方案基本上是这样的:
def get_children(self):
rel_objs = self._meta.get_all_related_objects()
return [getattr(self, x.get_accessor_name()) for x in rel_objs if x.model != type(self)]
虽然还有许多其他好的解决方案。您实际上可能想要基类的子项,而不仅仅是子类。如果没有,那里的答案可以作为您解决方案的动力。
答案 3 :(得分:1)
我能够使用__subclass__()
方法,但不能使用abtract=True
类。删除abstract=True
会将另一个表添加到您的数据库中(并且我会猜测更多的开销),但是然后您可以按照您的描述获取其所有子类。
答案 4 :(得分:1)
我意识到这是一种丑陋的解决方案,但我之前已经这样做了:
class ABClass(models.Model):
#common attributes
is_ABClass = True
class Meta:
abstract = True
class ConcreteClass1(ABClass):
#implementation specific attributes
class ConcreteClass2(ABClass):
#implementation specific attributes
class ModifiedConcreteClass1(ConcreteClass1):
#implementation specific attributes
def get_ABClasses():
this = modules[__name__]
return [getattr(this, attr) for attr in dir(this)
if hasattr(getattr(this, attr), 'is_ABClass') and attr != 'ABClass']