Changed methods used for traversing subclasses and superclasses of a given model.

Now uses model._meta.parents to determine superclasses.  _meta.parents is a dict of superclass: field_to_superclass pairs.

By using the field name of field_to_superclass, we can work out the field to use the django_polymorphic accessor on, even if a user-specified OneToOneField to parent is is used (with parent_link=True) to get to the parent in the inheritance hierarachy.

For subclasses, the path to the subclasses can be manually specified by the user if they use a 'related_name' on the OneToOneField from the subclass to the superclass.  I have changed the code to also support 'related_name' if present
fix_request_path_info
hottwaj 2014-02-18 18:00:18 +00:00
parent b73f22f4e0
commit 3e718d305e
1 changed files with 21 additions and 14 deletions

View File

@ -173,27 +173,34 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
"""helper function for __init__: """helper function for __init__:
determine names of all Django inheritance accessor member functions for type(self)""" determine names of all Django inheritance accessor member functions for type(self)"""
def add_model(model, as_ptr, result): def add_model(model, field_name, result):
name = model.__name__.lower() result[field_name] = model
if as_ptr:
name += '_ptr'
result[name] = model
def add_model_if_regular(model, as_ptr, result): def add_model_if_regular(model, field_name, result):
if (issubclass(model, models.Model) if (issubclass(model, models.Model)
and model != models.Model and model != models.Model
and model != self.__class__ and model != self.__class__
and model != PolymorphicModel): and model != PolymorphicModel):
add_model(model, as_ptr, result) add_model(model, field_name, result)
def add_all_super_models(model, result): def add_all_super_models(model, result):
add_model_if_regular(model, True, result) for super_cls, field_to_super in model._meta.parents.iteritems():
for b in model.__bases__: field_name = field_to_super.name #the field on model can have a different name to super_cls._meta.module_name, if the field is created manually using 'parent_link'
add_all_super_models(b, result) add_model_if_regular(super_cls, field_name, result)
add_all_super_models(super_cls, result)
def add_all_sub_models(model, result): def add_all_sub_models(super_cls, result):
for b in model.__subclasses__(): for sub_cls in super_cls.__subclasses__(): #go through all subclasses of model
add_model_if_regular(b, False, result) field_to_super = sub_cls._meta.parents[super_cls] #get the field that links sub_cls to super_cls
super_to_sub_related_field = field_to_super.rel
if super_to_sub_related_field.related_name is None:
#if related name is None the related field is the name of the subclass
to_subclass_fieldname = sub_cls.__name__.lower()
else:
#otherwise use the given related name
to_subclass_fieldname = super_to_sub_related_field.related_name
add_model_if_regular(sub_cls, to_subclass_fieldname, result)
result = {} result = {}
add_all_super_models(self.__class__, result) add_all_super_models(self.__class__, result)