Django:获取抽象基类的所有实现

pis*_*lis 12 django

我已经定义了一些看起来像这样的模型:

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
Run Code Online (Sandbox Code Playgroud)

我有一个视图,它采用'type'参数,指定要显示的类的类型.如果'type = None',我想显示ABClass的所有后代(在本例中为ConcreteClass {1,2},ModifiedConcreteClass1).我在文档中搜索过,似乎无法找到一种不需要维护ConcreteClasses列表的方法.ABClass.__subclasses__()看起来很有希望,但是当我打电话时它会返回一个空列表.

目前我最好的策略是在models.py中创建一个CLASS_LIST变量,该变量在运行时使用inspect方法填充ABClass的所有后代.有没有办法使用django api做到这一点?

谢谢

uta*_*ngo 6

如果你有的话'django.contrib.contenttypes',已经维护了一个ConcreteClasses列表INSTALLED_APPS.

我是这样做的:

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
Run Code Online (Sandbox Code Playgroud)

当你需要一个子类列表时,只需要调用ABClass.get_subclasses().

我使用它与具体的基类,但我没有看到这个不与抽象的一起工作的原因.

即使您的具体子类位于不同的Django应用程序中,此方法仍然有效.但请注意,它们app_label应与基类相同,因此代码get_subclasses()可以找到它们.


Bar*_*tek 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__()
Run Code Online (Sandbox Code Playgroud)

结果是

[<class '__main__.ConcreteClass1'>, <class '__main__.ConcreteClass2'>]
Run Code Online (Sandbox Code Playgroud)

不使用ABCMeta __metaclass__,您将收到一个空列表.

你可以在这里阅读一些很好的描述.只有这个问题,我不确定它是否会影响你是我无法弄清楚为什么当我创建一个ABClass的实例时,它找不到子类.也许通过玩一下并阅读更多的文档,它可能会让你在某个地方.

让我知道这对你有什么用,因为我对真正的答案真的很好奇.

  • 这与django的ORM无关. (2认同)
  • 这与ORM有什么关系?看起来他只是想获取子类。 (2认同)

Pau*_*lan 5

看看这个类似的问题:

如何在不知道子类名称的情况下访问django中对象的子类?

我的解决方案基本上是这样的:

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)]
Run Code Online (Sandbox Code Playgroud)

虽然那里还有许多其他好的解决方案.您实际上可能想要基类的子项,而不仅仅是子类.如果没有,那里的答案可以作为您解决方案的动力.