make sure 'base_manager is not inherited (but managed by Django instead).
(This seems more correct but it doen't seem to make any difference.) Also added related test cases.
This commit is contained in:
+3
-1
@@ -92,9 +92,11 @@ class PolymorphicModelBase(ModelBase):
|
||||
for key, manager in base.__dict__.items():
|
||||
if type(manager) == models.manager.ManagerDescriptor: manager = manager.manager
|
||||
if not isinstance(manager, models.Manager): continue
|
||||
if key in ['_base_manager']: continue # let Django handle _base_manager
|
||||
if key in attrs: continue
|
||||
if key in add_managers_keys: continue # manager with that name already added, skip
|
||||
if manager._inherited: continue # inherited managers have no significance, they are just copies
|
||||
if manager._inherited: continue # inherited managers (on the bases) have no significance, they are just copies
|
||||
#print >>sys.stderr,'##',self.__name__, key
|
||||
if isinstance(manager, PolymorphicManager): # validate any inherited polymorphic managers
|
||||
self.validate_model_manager(manager, self.__name__, key)
|
||||
add_managers.append((base.__name__, key, manager))
|
||||
|
||||
@@ -135,25 +135,24 @@ class PolymorphicModel(models.Model):
|
||||
our appropriate base_objects manager.
|
||||
"""
|
||||
super(PolymorphicModel, self).__init__(*args, ** kwargs)
|
||||
|
||||
if self.__class__.polymorphic_super_sub_accessors_replaced: return
|
||||
self.__class__.polymorphic_super_sub_accessors_replaced = True
|
||||
|
||||
def create_accessor_function_for_model(model):
|
||||
def create_accessor_function_for_model(model, accessor_name):
|
||||
def accessor_function(self):
|
||||
attr = model.base_objects.get(pk=self.pk)
|
||||
return attr
|
||||
return accessor_function
|
||||
|
||||
subclasses_and_superclasses_accessors = self.get_inheritance_relation_fields_and_models()
|
||||
#print '###',self.__class__.__name__,subclasses_and_superclasses_accessors
|
||||
|
||||
from django.db.models.fields.related import SingleRelatedObjectDescriptor, ReverseSingleRelatedObjectDescriptor
|
||||
|
||||
for name,model in subclasses_and_superclasses_accessors.iteritems():
|
||||
orig_accessor = getattr(self.__class__, name, None)
|
||||
if type(orig_accessor) in [SingleRelatedObjectDescriptor,ReverseSingleRelatedObjectDescriptor]:
|
||||
#print 'replacing',name, orig_accessor
|
||||
setattr(self.__class__, name, property(create_accessor_function_for_model(model)) )
|
||||
#print >>sys.stderr, '---------- replacing',name, orig_accessor
|
||||
setattr(self.__class__, name, property(create_accessor_function_for_model(model, name)) )
|
||||
|
||||
def get_inheritance_relation_fields_and_models(self):
|
||||
"""helper function for __init__:
|
||||
|
||||
+70
-12
@@ -4,6 +4,7 @@
|
||||
"""
|
||||
|
||||
import settings
|
||||
import sys
|
||||
|
||||
from django.test import TestCase
|
||||
from django.db.models.query import QuerySet
|
||||
@@ -29,6 +30,8 @@ class Model2B(Model2A):
|
||||
field2 = models.CharField(max_length=10)
|
||||
class Model2C(Model2B):
|
||||
field3 = models.CharField(max_length=10)
|
||||
class Model2D(Model2C):
|
||||
field4 = models.CharField(max_length=10)
|
||||
|
||||
class ModelShow1(ShowFieldType,PolymorphicModel):
|
||||
field1 = models.CharField(max_length=10)
|
||||
@@ -84,6 +87,13 @@ class RelationBC(RelationB):
|
||||
class RelatingModel(models.Model):
|
||||
many2many = models.ManyToManyField(Model2A)
|
||||
|
||||
class One2OneRelatingModel(PolymorphicModel):
|
||||
one2one = models.OneToOneField(Model2A)
|
||||
field1 = models.CharField(max_length=10)
|
||||
|
||||
class One2OneRelatingModelDerived(One2OneRelatingModel):
|
||||
field2 = models.CharField(max_length=10)
|
||||
|
||||
class MyManager(PolymorphicManager):
|
||||
def get_query_set(self):
|
||||
return super(MyManager, self).get_query_set().order_by('-field1')
|
||||
@@ -242,6 +252,9 @@ class testclass(TestCase):
|
||||
entry1 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2')
|
||||
entry2 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2')
|
||||
|
||||
|
||||
def show_base_manager(model):
|
||||
print type(model._base_manager),model._base_manager.model
|
||||
|
||||
__test__ = {"doctest": """
|
||||
#######################################################
|
||||
@@ -249,19 +262,18 @@ __test__ = {"doctest": """
|
||||
|
||||
>>> settings.DEBUG=True
|
||||
|
||||
#>>> get_version()
|
||||
#'1.0 rc1'
|
||||
|
||||
|
||||
### simple inheritance
|
||||
|
||||
>>> o=Model2A.objects.create(field1='A1')
|
||||
>>> o=Model2B.objects.create(field1='B1', field2='B2')
|
||||
>>> o=Model2C.objects.create(field1='C1', field2='C2', field3='C3')
|
||||
|
||||
[ <Model2A: id 1, field1 (CharField)>,
|
||||
>>> o=Model2D.objects.create(field1='D1', field2='D2', field3='D3', field4='D4')
|
||||
>>> Model2A.objects.all()
|
||||
[ <Model2A: id 1, field1 (CharField)>,
|
||||
<Model2B: id 2, field1 (CharField), field2 (CharField)>,
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>,
|
||||
<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)> ]
|
||||
|
||||
# manual get_real_instance()
|
||||
>>> o=Model2A.base_objects.get(field1='C1')
|
||||
@@ -269,6 +281,48 @@ __test__ = {"doctest": """
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>
|
||||
|
||||
|
||||
### test inheritance pointers & _base_managers
|
||||
|
||||
>>> show_base_manager(PlainA)
|
||||
<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainA'>
|
||||
>>> show_base_manager(PlainB)
|
||||
<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainB'>
|
||||
>>> show_base_manager(PlainC)
|
||||
<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainC'>
|
||||
>>> show_base_manager(Model2A)
|
||||
<class 'polymorphic.manager.PolymorphicManager'> <class 'polymorphic.tests.Model2A'>
|
||||
>>> show_base_manager(Model2B)
|
||||
<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2B'>
|
||||
>>> show_base_manager(Model2C)
|
||||
<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2C'>
|
||||
>>> show_base_manager(One2OneRelatingModel)
|
||||
<class 'polymorphic.manager.PolymorphicManager'> <class 'polymorphic.tests.One2OneRelatingModel'>
|
||||
>>> show_base_manager(One2OneRelatingModelDerived)
|
||||
<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.One2OneRelatingModelDerived'>
|
||||
|
||||
>>> o=Model2A.base_objects.get(field1='C1')
|
||||
>>> o.model2b
|
||||
<Model2B: id 3, field1 (CharField), field2 (CharField)>
|
||||
|
||||
>>> o=Model2B.base_objects.get(field1='C1')
|
||||
>>> o.model2c
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>
|
||||
|
||||
|
||||
### OneToOneField, test both directions for polymorphism
|
||||
|
||||
>>> a=Model2A.base_objects.get(field1='C1')
|
||||
>>> b=One2OneRelatingModelDerived.objects.create(one2one=a, field1='f1', field2='f2')
|
||||
>>> b.one2one # this result is basically wrong, probably due to Django cacheing (we used base_objects), but should not be a problem
|
||||
<Model2A: id 3, field1 (CharField)>
|
||||
>>> c=One2OneRelatingModelDerived.objects.get(field1='f1')
|
||||
>>> c.one2one
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>
|
||||
|
||||
>>> a.one2onerelatingmodel
|
||||
<One2OneRelatingModelDerived: One2OneRelatingModelDerived object>
|
||||
|
||||
|
||||
### ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent, also with annotate()
|
||||
|
||||
>>> o=ModelShow1.objects.create(field1='abc')
|
||||
@@ -315,15 +369,18 @@ __test__ = {"doctest": """
|
||||
|
||||
>>> Model2A.objects.instance_of(Model2B)
|
||||
[ <Model2B: id 2, field1 (CharField), field2 (CharField)>,
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>,
|
||||
<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)> ]
|
||||
|
||||
>>> Model2A.objects.filter(instance_of=Model2B)
|
||||
[ <Model2B: id 2, field1 (CharField), field2 (CharField)>,
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>,
|
||||
<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)> ]
|
||||
|
||||
>>> Model2A.objects.filter(Q(instance_of=Model2B))
|
||||
[ <Model2B: id 2, field1 (CharField), field2 (CharField)>,
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>,
|
||||
<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)> ]
|
||||
|
||||
>>> Model2A.objects.not_instance_of(Model2B)
|
||||
[ <Model2A: id 1, field1 (CharField)> ]
|
||||
@@ -345,7 +402,8 @@ __test__ = {"doctest": """
|
||||
>>> oa.delete()
|
||||
>>> Model2A.objects.all()
|
||||
[ <Model2A: id 1, field1 (CharField)>,
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>,
|
||||
<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)> ]
|
||||
|
||||
|
||||
### queryset combining
|
||||
@@ -405,8 +463,8 @@ __test__ = {"doctest": """
|
||||
>>> o=ModelWithMyManager.objects.create(field1='D1b', field4='D4b')
|
||||
|
||||
>>> ModelWithMyManager.objects.all()
|
||||
[ <ModelWithMyManager: id 5, field1 (CharField): "D1b", field4 (CharField): "D4b">,
|
||||
<ModelWithMyManager: id 4, field1 (CharField): "D1a", field4 (CharField): "D4a"> ]
|
||||
[ <ModelWithMyManager: id 6, field1 (CharField): "D1b", field4 (CharField): "D4b">,
|
||||
<ModelWithMyManager: id 5, field1 (CharField): "D1a", field4 (CharField): "D4a"> ]
|
||||
|
||||
>>> type(ModelWithMyManager.objects)
|
||||
<class 'polymorphic.tests.MyManager'>
|
||||
|
||||
Reference in New Issue
Block a user