fix "...has no attribute 'sub_and_superclass_dict'". Thanks to Mattias Brändström.

this occurred if a subclass defined __init__ and accessed class
members before calling the superclass __init__
(__getattribute__ had a problem, as "sub_and_superclass_dict" was set in __init__).
fix_request_path_info
Bert Constantin 2010-02-18 17:44:33 +01:00
parent 7e584632b8
commit e6c1e7ec6e
3 changed files with 44 additions and 30 deletions

View File

@ -34,3 +34,4 @@ if not (django_VERSION[0]<=1 and django_VERSION[1]<=1):
field2 = models.CharField(max_length=10) field2 = models.CharField(max_length=10)
class Model2C(Model2B): class Model2C(Model2B):
field3 = models.CharField(max_length=10) field3 = models.CharField(max_length=10)

View File

@ -676,9 +676,33 @@ class PolymorphicModel(models.Model):
# django.db.models.base._collect_sub_objects: parent_obj = getattr(self, link.name) # django.db.models.base._collect_sub_objects: parent_obj = getattr(self, link.name)
# TODO: investigate Django how this can be avoided # TODO: investigate Django how this can be avoided
def __getattribute__(self, name): def __getattribute__(self, name):
if name != '__class__': if not name.startswith('__'): # do not intercept __class__ etc.
#if name.endswith('_ptr_cache'): # unclear if this should be handled as well
model = self.__class__.sub_and_superclass_dict.get(name, None) # for efficiency: create a dict containing all model attribute names we need to intercept
# (do this only once and store the result into self.__class__.inheritance_relation_fields_dict)
if not self.__class__.__dict__.get('inheritance_relation_fields_dict', None):
def add_if_regular_sub_or_super_class(model, as_ptr, result):
if ( issubclass(model, models.Model) and model != models.Model
and model != self.__class__ and model != PolymorphicModel):
name = model.__name__.lower()
if as_ptr: name+='_ptr'
result[name] = model
def add_all_base_models(model, result):
add_if_regular_sub_or_super_class(model, True, result)
for b in model.__bases__:
add_all_base_models(b, result)
def add_sub_models(model, result):
for b in model.__subclasses__():
add_if_regular_sub_or_super_class(b, False, result)
result = {}
add_all_base_models(self.__class__,result)
add_sub_models(self.__class__,result)
#print '##',self.__class__.__name__,' - ',result
self.__class__.inheritance_relation_fields_dict = result
model = self.__class__.inheritance_relation_fields_dict.get(name, None)
if model: if model:
id = super(PolymorphicModel, self).__getattribute__('id') id = super(PolymorphicModel, self).__getattribute__('id')
attr = model.base_objects.get(id=id) attr = model.base_objects.get(id=id)
@ -686,34 +710,7 @@ class PolymorphicModel(models.Model):
return attr return attr
return super(PolymorphicModel, self).__getattribute__(name) return super(PolymorphicModel, self).__getattribute__(name)
# support for __getattribute__ hack: create sub_and_superclass_dict,
# containing all model attribute names we need to intercept
# (do this once here instead of in __getattribute__ every time)
def __init__(self, *args, **kwargs):
if not self.__class__.__dict__.get('sub_and_superclass_dict', None):
def add_if_regular_sub_or_super_class(model, as_ptr, result):
if ( issubclass(model, models.Model) and model != models.Model
and model != self.__class__ and model != PolymorphicModel):
name = model.__name__.lower()
if as_ptr: name+='_ptr'
result[name] = model
def add_all_base_models(model, result):
add_if_regular_sub_or_super_class(model, True, result)
for b in model.__bases__:
add_all_base_models(b, result)
def add_sub_models(model, result):
for b in model.__subclasses__():
add_if_regular_sub_or_super_class(b, False, result)
result = {}
add_all_base_models(self.__class__,result)
add_sub_models(self.__class__,result)
#print '##',self.__class__.__name__,' - ',result
self.__class__.sub_and_superclass_dict = result
super(PolymorphicModel, self).__init__(*args, **kwargs)
def __repr__(self): def __repr__(self):
out = self.__class__.__name__ + ': id %d' % (self.pk or - 1) out = self.__class__.__name__ + ': id %d' % (self.pk or - 1)
for f in self._meta.fields: for f in self._meta.fields:

View File

@ -102,6 +102,15 @@ class BlogA_Entry(ShowFieldsAndTypes, PolymorphicModel):
class ModelFieldNameTest(PolymorphicModel): class ModelFieldNameTest(PolymorphicModel):
modelfieldnametest = models.CharField(max_length=10) modelfieldnametest = models.CharField(max_length=10)
class InitTestModel(PolymorphicModel):
bar = models.CharField(max_length=100)
def __init__(self, *args, **kwargs):
kwargs['bar'] = self.x()
super(InitTestModel, self).__init__(*args, **kwargs)
class InitTestModelSubclass(InitTestModel):
def x(self):
return 'XYZ'
# test bad field name # test bad field name
#class TestBadFieldModel(PolymorphicModel): #class TestBadFieldModel(PolymorphicModel):
# instance_of = models.CharField(max_length=10) # instance_of = models.CharField(max_length=10)
@ -310,6 +319,13 @@ __test__ = {"doctest": """
>>> ModelFieldNameTest.objects.create(modelfieldnametest='1') >>> ModelFieldNameTest.objects.create(modelfieldnametest='1')
<ModelFieldNameTest: id 1, modelfieldnametest (CharField)> <ModelFieldNameTest: id 1, modelfieldnametest (CharField)>
### fixed issue in PolymorphicModel.__getattribute__:
# if subclass defined __init__ and accessed class members, __getattribute__ had a problem: "...has no attribute 'sub_and_superclass_dict'"
#>>> o
>>> o = InitTestModelSubclass.objects.create()
>>> o.bar
'XYZ'
### Django model inheritance diamond problem, fails for Django 1.1 ### Django model inheritance diamond problem, fails for Django 1.1
#>>> o=DiamondXY.objects.create(field_b='b', field_x='x', field_y='y') #>>> o=DiamondXY.objects.create(field_b='b', field_x='x', field_y='y')