Find object in child class from object in parent class in django

后端 未结 6 1664
春和景丽
春和景丽 2021-01-02 17:46

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

相关标签:
6条回答
  • 2021-01-02 18:03

    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.

    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.

    0 讨论(0)
  • 2021-01-02 18:07

    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:

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

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

    0 讨论(0)
  • 2021-01-02 18:08

    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.

    0 讨论(0)
  • 2021-01-02 18:09

    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!

    0 讨论(0)
  • 2021-01-02 18:17

    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...

    0 讨论(0)
  • 2021-01-02 18:18

    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:

    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
    
    0 讨论(0)
提交回复
热议问题