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...@jabber.rwth-aachen.de
or
http://bronger-jmp.appspot.com