在django中从父类中的对象查找子类中的对象

时间:2021-02-27 16:08:02

Let's say I have a parent class (ThingsThatMigrate) and two children (Coconut and Swallow). Now let's say I have a ThingsThatMigrate object. How can I determine if it is in fact a Coconut or a Swallow? Once having done so, how can I get to the Coconut or Swallow object?

假设我有一个父类(ThingsThatMigrate)和两个孩子(Coconut和Swallow)。现在让我们说我有一个ThingsThatMigrate对象。我怎样才能确定它实际上是椰子还是燕子?一旦这样做,我怎样才能到达椰子或燕子物体?

6 个解决方案

#1


7  

Django doesn't offer such model polymorphism out of the box.The easiest way to do what you are trying to achieve is to store the content type of a new object in it. There's a simple generic app called django-polymorphic-models which offers you this functionality - and - additionally a downcast-method that will return the child object!

Django并不提供开箱即用的模型多态性。您尝试实现的最简单方法是在其中存储新对象的内容类型。有一个简单的通用应用程序叫做django-polymorphic-models,它为你提供了这个功能 - 另外还有一个将返回子对象的downcast方法!

#2


2  

Concrete or abstract inheritance? If concrete:

具体还是抽象的继承?如果具体:

>>> things = ThingsThatMigrate.objects.all().select_related('coconut', 'swallow')
>>> for thing in things:
...     thing = thing.coconut or thing.swallow or thing
...     print thing

This can be automated using django-model-utils InheritanceManager (then you don't need to worry about select_related or manually listing all possible subclasses). Maintained by another Django core developer.

这可以使用django-model-utils InheritanceManager自动执行(然后您不必担心select_related或手动列出所有可能的子类)。由另一位Django核心开发人员维护。

#3


0  

It's not particularly pretty or efficient, but the best way I can think of implementing this without storing the subclass meta data in the DB (like django-polymorphic-models does) would be a child() method in your ThingsThatMigrate model class:

它不是特别漂亮或高效,但是我可以想到实现这一点而不将子类元数据存储在数据库中的最佳方式(如django-polymorphic-models)将是您的ThingsThatMigrate模型类中的child()方法:

from django.core.exceptions import ObjectDoesNotExist

def child(self):
    for subclass in self.__class__.__subclasses__():
        try:
            return getattr(self, subclass.__name__.lower())
        except (AttributeError, ObjectDoesNotExist):
            continue

#4


0  

On a Django CMS I work with (Merengue http://www.merengueproject.org/), we store the "classname" attribute that stores what is the real class of the object.

在我使用的Django CMS上(Merengue http://www.merengueproject.org/),我们存储了“classname”属性,该属性存储了对象的真实类。

In order to get the real instance we used the following method:

为了获得真实实例,我们使用了以下方法:

    def get_real_instance(self):
        """ get object child instance """
        def get_subclasses(cls):
            subclasses = cls.__subclasses__()
            result = []
            for subclass in subclasses:
                if not subclass._meta.abstract:
                    result.append(subclass)
                else:
                    result += get_subclasses(subclass)
            return result

        if hasattr(self, '_real_instance'):  # try looking in our cache
            return self._real_instance
        subclasses = get_subclasses(self.__class__)
        if not subclasses:  # already real_instance
            self._real_instance = getattr(self, self.class_name, self)
            return self._real_instance
        else:
            subclasses_names = [cls.__name__.lower() for cls in subclasses]
            for subcls_name in subclasses_names:
                if hasattr(self, subcls_name):
                    return getattr(self, subcls_name, self).get_real_instance()
            return self

The important thing of this function is that it keeps in mind if the class is abstract or not, wich change the logic a little bit.

这个函数的重要之处在于,如果类是抽象的,它会记住,这会改变逻辑。

#5


0  

As DrMeer suggested, I highly recommend django-model-utils (hosted on bitbucket now though). I'm not sure it's convincing enough though.
Let a code example prove it:

正如DrMeer建议的那样,我强烈推荐django-model-utils(尽管现在托管在bitbucket上)。我不确定它是否足够令人信服。让代码示例证明:

>>> ThingsThatMigrate.objects.all().select_subclasses()
Coconut, Coconut, Swallow, Coconut, ThingsThatMigrate

It takes one line, objects = InheritanceManager() in your parent model.

在父模型中需要一行,objects = InheritanceManager()。

#6


-2  

From the docs:

来自文档:

If you have a Place that is also a Restaurant, you can get from the Place object to the Restaurant object by using the lower-case version of the model name...

如果你有一个Place也是一个餐厅,你可以使用模型名称的小写版本从Place对象到Restaurant对象...

#1


7  

Django doesn't offer such model polymorphism out of the box.The easiest way to do what you are trying to achieve is to store the content type of a new object in it. There's a simple generic app called django-polymorphic-models which offers you this functionality - and - additionally a downcast-method that will return the child object!

Django并不提供开箱即用的模型多态性。您尝试实现的最简单方法是在其中存储新对象的内容类型。有一个简单的通用应用程序叫做django-polymorphic-models,它为你提供了这个功能 - 另外还有一个将返回子对象的downcast方法!

#2


2  

Concrete or abstract inheritance? If concrete:

具体还是抽象的继承?如果具体:

>>> things = ThingsThatMigrate.objects.all().select_related('coconut', 'swallow')
>>> for thing in things:
...     thing = thing.coconut or thing.swallow or thing
...     print thing

This can be automated using django-model-utils InheritanceManager (then you don't need to worry about select_related or manually listing all possible subclasses). Maintained by another Django core developer.

这可以使用django-model-utils InheritanceManager自动执行(然后您不必担心select_related或手动列出所有可能的子类)。由另一位Django核心开发人员维护。

#3


0  

It's not particularly pretty or efficient, but the best way I can think of implementing this without storing the subclass meta data in the DB (like django-polymorphic-models does) would be a child() method in your ThingsThatMigrate model class:

它不是特别漂亮或高效,但是我可以想到实现这一点而不将子类元数据存储在数据库中的最佳方式(如django-polymorphic-models)将是您的ThingsThatMigrate模型类中的child()方法:

from django.core.exceptions import ObjectDoesNotExist

def child(self):
    for subclass in self.__class__.__subclasses__():
        try:
            return getattr(self, subclass.__name__.lower())
        except (AttributeError, ObjectDoesNotExist):
            continue

#4


0  

On a Django CMS I work with (Merengue http://www.merengueproject.org/), we store the "classname" attribute that stores what is the real class of the object.

在我使用的Django CMS上(Merengue http://www.merengueproject.org/),我们存储了“classname”属性,该属性存储了对象的真实类。

In order to get the real instance we used the following method:

为了获得真实实例,我们使用了以下方法:

    def get_real_instance(self):
        """ get object child instance """
        def get_subclasses(cls):
            subclasses = cls.__subclasses__()
            result = []
            for subclass in subclasses:
                if not subclass._meta.abstract:
                    result.append(subclass)
                else:
                    result += get_subclasses(subclass)
            return result

        if hasattr(self, '_real_instance'):  # try looking in our cache
            return self._real_instance
        subclasses = get_subclasses(self.__class__)
        if not subclasses:  # already real_instance
            self._real_instance = getattr(self, self.class_name, self)
            return self._real_instance
        else:
            subclasses_names = [cls.__name__.lower() for cls in subclasses]
            for subcls_name in subclasses_names:
                if hasattr(self, subcls_name):
                    return getattr(self, subcls_name, self).get_real_instance()
            return self

The important thing of this function is that it keeps in mind if the class is abstract or not, wich change the logic a little bit.

这个函数的重要之处在于,如果类是抽象的,它会记住,这会改变逻辑。

#5


0  

As DrMeer suggested, I highly recommend django-model-utils (hosted on bitbucket now though). I'm not sure it's convincing enough though.
Let a code example prove it:

正如DrMeer建议的那样,我强烈推荐django-model-utils(尽管现在托管在bitbucket上)。我不确定它是否足够令人信服。让代码示例证明:

>>> ThingsThatMigrate.objects.all().select_subclasses()
Coconut, Coconut, Swallow, Coconut, ThingsThatMigrate

It takes one line, objects = InheritanceManager() in your parent model.

在父模型中需要一行,objects = InheritanceManager()。

#6


-2  

From the docs:

来自文档:

If you have a Place that is also a Restaurant, you can get from the Place object to the Restaurant object by using the lower-case version of the model name...

如果你有一个Place也是一个餐厅,你可以使用模型名称的小写版本从Place对象到Restaurant对象...