Hallöchen!

Daniel Roseman writes:

> [...]
>
> This is the expected behaviour. You've asked for an Author object,
> so that's what you've got. There's no way to tell from the Author
> model that this particular instance of it is also an instance of
> Translator.

More and more I get the impression that this is a significant use
case.  Again, here is how we solved it: Append the following source
code to your models.py and call instance.find_actual_instance(),
then you get the, well, actual instance.  Maybe something like this
should become part of Django?  The clean solution is to use
contenttypes instead of the "try all subclasses" trick, though.  I
just haven't had time to do it.


_globals = copy.copy(globals())
all_models = [cls for cls in _globals.values() if inspect.isclass(cls) and 
issubclass(cls, models.Model)]
class_hierarchy = inspect.getclasstree(all_models)
def find_actual_instance(self):
    u"""This is a module function but is is injected into ``Models.model`` to
    become a class method for all models of Chantal.  If you call this method
    on a database instance, you get the leaf class instance of this
    model.  This way, polymorphism actually works with the
    relational database.

    :Return:
      an instance of the actual model class for this database entry.

    :rtype: ``models.Model``.
    """
    try:
        return self.__actual_instance
    except AttributeError:
        if not self.direct_subclasses:
            self.__actual_instance = self
        else:
            for cls in self.direct_subclasses:
                name = cls.__name__.lower()
                if hasattr(self, name):
                    instance = getattr(self, name)
                    self.__actual_instance = instance.find_actual_instance()
                    break
            else:
                raise Exception("internal error: instance not found")
        return self.__actual_instance

models.Model.find_actual_instance = find_actual_instance


def inject_direct_subclasses(parent, hierarchy):
    u"""This is a mere helper function which injects a list with all subclasses
    into the class itself, under the name ``direct_subclasses``.  It is only
    for use by `find_actual_instance`.

    This is basically a tree walker through the weird nested data structure
    returned by ``inspect.getclasstree`` and stored in `class_hierarchy`.

    :Parameters:
      - `parent`: the class to which the subclasses should be added
      - `hierarchy`: the remaining class inheritance hierarchy that has to be
        processed.

    :type parent: class, descendant of ``models.Model``
    :type hierarchy: list as returned by ``inspect.getclasstree``
    """
    i = 0
    while i < len(hierarchy):
        # May have already been initialised by another app
        if "direct_subclasses" not in hierarchy[i][0].__dict__:
            hierarchy[i][0].direct_subclasses = set()
        if parent:
            parent.direct_subclasses.add(hierarchy[i][0])
        if i + 1 < len(hierarchy) and isinstance(hierarchy[i+1], list):
            inject_direct_subclasses(hierarchy[i][0], hierarchy[i+1])
            i += 2
        else:
            i += 1

inject_direct_subclasses(None, class_hierarchy)
del _globals, cls



Tschö,
Torsten.

-- 
Torsten Bronger, aquisgrana, europa vetus
                   Jabber ID: torsten.bron...@jabber.rwth-aachen.de
                                  or http://bronger-jmp.appspot.com

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-us...@googlegroups.com.
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en.

Reply via email to