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.
fix_request_path_info
Bert Constantin 2010-10-22 12:11:34 +02:00
parent 6628145af7
commit b2357592cb
5 changed files with 77 additions and 20 deletions

View File

@ -213,7 +213,6 @@ ul.auto-toc {
<div class="section" id="polymorphic-models-for-django">
<h1>Polymorphic Models for Django</h1>
<p>.</p>
<div class="section" id="quick-start-docs-contributing">
<h2>Quick Start, Docs, Contributing</h2>
<ul class="simple">

View File

@ -1,7 +1,6 @@
Polymorphic Models for Django
=============================
.
Quick Start, Docs, Contributing
-------------------------------

View File

@ -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))

View File

@ -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__:

View File

@ -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')
@ -243,25 +253,27 @@ class testclass(TestCase):
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": """
#######################################################
### Tests
>>> 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'>