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

时间:2023-01-09 06:49:07

I have defined some models which look like this:

我定义了一些像这样的模型:

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

I have a view which takes a 'type' parameter which specifies the type of class to display. If 'type=None' I want to display all descendents of ABClass (in this case, ConcreteClass{1,2}, ModifiedConcreteClass1). I have poked around the documentation and cannot seem to find a way of doing this which does not require list of ConcreteClasses be maintained. ABClass.__subclasses__() seemed promising but it returns an empty list when I call it.

我有一个视图,它接受一个“type”参数,该参数指定要显示的类的类型。如果“type=None”,我想显示ABClass的所有后代(在本例中,concrete lass{1,2}, modifiedteclass1)。我仔细查阅了文件,似乎找不到一种不需要维护混凝土清单的方法。@ ABClass.__subclasses__()看起来很有前途,但当我调用它时,它会返回一个空列表。

At present the best strategy I have is to create a CLASS_LIST variable in models.py which is populated with all descendents of ABClass at runtime using inspect methods. Is there a way to do this using the django api?

目前我的最佳策略是在模型中创建CLASS_LIST变量。py在运行时使用inspect方法填充ABClass的所有后代。是否有使用django api来实现这一点的方法?

Thanks

谢谢

5 个解决方案

#1


5  

Take a look at this similar question:

看看这个类似的问题:

How do I access the child classes of an object in django without knowing the name of the child class?

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

My solution to that was essentially this:

我的解决方案是:

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)]

Though there are a number of other good solutions there as well. It seems likely that you actually want the children of the base class, and not just the child classes. If not, the answers there may serve as a motivator for your solution.

虽然也有其他一些好的解决方案。似乎您实际上希望的是基类的子类,而不仅仅是子类。如果答案是否定的,那么答案可能会成为你解决问题的动力。

#2


5  

I haven't look at what Django does when you set abstract True in the backend, but I played with this and I found that this works. Please note, it only works in Python 2.6

我还没有看到Django在后台设置抽象的True时做了什么,但是我使用了这个,我发现它是有效的。请注意,它只适用于Python 2.6

from abc import ABCMeta

class ABClass():
    __metaclass__ = ABCMeta

class ConcreteClass1(ABClass):
     pass

class ConcreteClass2(ABClass):
     pass

print ABClass.__subclasses__()

Results in

结果

[<class '__main__.ConcreteClass1'>, <class '__main__.ConcreteClass2'>]

Without using the ABCMeta and __metaclass__, you will receive an empty list.

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

You can read a good description of what's going on here. Only problem with this, and I'm not sure if it will affect you is I can't quite figure out why when I create an instance of ABClass, it can't find the subclasses. Perhaps by playing around a bit and reading the doc more it might get you somewhere.

你可以读一下这里发生的事情的详细描述。只有这个问题,我不确定它是否会影响到你我不知道为什么当我创建ABClass的实例时,它找不到子类。也许你可以多玩玩,多读读医生的书,这样你就会有所收获。

Let me know how this works for you, as I am genuinely curious on the true answer.

让我知道这对你有什么作用,因为我真的很想知道真正的答案。

#3


4  

A list of ConcreteClasses is already maintained if you have 'django.contrib.contenttypes' in INSTALLED_APPS.

如果你有“django.com .后悔”的话,一份混凝土清单已经被维护了。在INSTALLED_APPS contenttypes”。

Here is how I do it:

我是这样做的:

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

When you need a list of subclasses, just call ABClass.get_subclasses().

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

I am using this with concrete base classes, but I don't see a reason for this not to work with abstract ones.

我正在具体的基类中使用它,但是我认为没有理由不使用抽象类。

This approach works even if your concrete subclasses are in different Django apps. Note however that they shoud have the same app_label as the base class so the code in get_subclasses() can find them.

即使具体的子类在不同的Django应用程序中,这种方法仍然有效。但是请注意,它们应该具有与基类相同的app_label,以便get_subclasses()中的代码可以找到它们。

#4


1  

I was able to use the __subclass__() method but not on an abtract=True class. Removing the abstract=True will add another table to your database (and more overhead, I would guess) but but then you can get all its subclasses as you described.

我可以使用__subclass__()方法,但不能使用abtract=True类。删除abstract=True将向数据库添加另一个表(我猜可能会有更多的开销),但是这样您就可以得到您描述的所有子类。

#5


1  

I realize that this is kind of an ugly solution, but I've done this before:

我意识到这是一种丑陋的解决方案,但我以前做过:

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']

#1


5  

Take a look at this similar question:

看看这个类似的问题:

How do I access the child classes of an object in django without knowing the name of the child class?

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

My solution to that was essentially this:

我的解决方案是:

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)]

Though there are a number of other good solutions there as well. It seems likely that you actually want the children of the base class, and not just the child classes. If not, the answers there may serve as a motivator for your solution.

虽然也有其他一些好的解决方案。似乎您实际上希望的是基类的子类,而不仅仅是子类。如果答案是否定的,那么答案可能会成为你解决问题的动力。

#2


5  

I haven't look at what Django does when you set abstract True in the backend, but I played with this and I found that this works. Please note, it only works in Python 2.6

我还没有看到Django在后台设置抽象的True时做了什么,但是我使用了这个,我发现它是有效的。请注意,它只适用于Python 2.6

from abc import ABCMeta

class ABClass():
    __metaclass__ = ABCMeta

class ConcreteClass1(ABClass):
     pass

class ConcreteClass2(ABClass):
     pass

print ABClass.__subclasses__()

Results in

结果

[<class '__main__.ConcreteClass1'>, <class '__main__.ConcreteClass2'>]

Without using the ABCMeta and __metaclass__, you will receive an empty list.

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

You can read a good description of what's going on here. Only problem with this, and I'm not sure if it will affect you is I can't quite figure out why when I create an instance of ABClass, it can't find the subclasses. Perhaps by playing around a bit and reading the doc more it might get you somewhere.

你可以读一下这里发生的事情的详细描述。只有这个问题,我不确定它是否会影响到你我不知道为什么当我创建ABClass的实例时,它找不到子类。也许你可以多玩玩,多读读医生的书,这样你就会有所收获。

Let me know how this works for you, as I am genuinely curious on the true answer.

让我知道这对你有什么作用,因为我真的很想知道真正的答案。

#3


4  

A list of ConcreteClasses is already maintained if you have 'django.contrib.contenttypes' in INSTALLED_APPS.

如果你有“django.com .后悔”的话,一份混凝土清单已经被维护了。在INSTALLED_APPS contenttypes”。

Here is how I do it:

我是这样做的:

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

When you need a list of subclasses, just call ABClass.get_subclasses().

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

I am using this with concrete base classes, but I don't see a reason for this not to work with abstract ones.

我正在具体的基类中使用它,但是我认为没有理由不使用抽象类。

This approach works even if your concrete subclasses are in different Django apps. Note however that they shoud have the same app_label as the base class so the code in get_subclasses() can find them.

即使具体的子类在不同的Django应用程序中,这种方法仍然有效。但是请注意,它们应该具有与基类相同的app_label,以便get_subclasses()中的代码可以找到它们。

#4


1  

I was able to use the __subclass__() method but not on an abtract=True class. Removing the abstract=True will add another table to your database (and more overhead, I would guess) but but then you can get all its subclasses as you described.

我可以使用__subclass__()方法,但不能使用abtract=True类。删除abstract=True将向数据库添加另一个表(我猜可能会有更多的开销),但是这样您就可以得到您描述的所有子类。

#5


1  

I realize that this is kind of an ugly solution, but I've done this before:

我意识到这是一种丑陋的解决方案,但我以前做过:

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']