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:
@@ -213,7 +213,6 @@ ul.auto-toc {
|
|||||||
|
|
||||||
<div class="section" id="polymorphic-models-for-django">
|
<div class="section" id="polymorphic-models-for-django">
|
||||||
<h1>Polymorphic Models for Django</h1>
|
<h1>Polymorphic Models for Django</h1>
|
||||||
<p>.</p>
|
|
||||||
<div class="section" id="quick-start-docs-contributing">
|
<div class="section" id="quick-start-docs-contributing">
|
||||||
<h2>Quick Start, Docs, Contributing</h2>
|
<h2>Quick Start, Docs, Contributing</h2>
|
||||||
<ul class="simple">
|
<ul class="simple">
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
Polymorphic Models for Django
|
Polymorphic Models for Django
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
.
|
|
||||||
|
|
||||||
Quick Start, Docs, Contributing
|
Quick Start, Docs, Contributing
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|||||||
+3
-1
@@ -92,9 +92,11 @@ class PolymorphicModelBase(ModelBase):
|
|||||||
for key, manager in base.__dict__.items():
|
for key, manager in base.__dict__.items():
|
||||||
if type(manager) == models.manager.ManagerDescriptor: manager = manager.manager
|
if type(manager) == models.manager.ManagerDescriptor: manager = manager.manager
|
||||||
if not isinstance(manager, models.Manager): continue
|
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 attrs: continue
|
||||||
if key in add_managers_keys: continue # manager with that name already added, skip
|
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
|
if isinstance(manager, PolymorphicManager): # validate any inherited polymorphic managers
|
||||||
self.validate_model_manager(manager, self.__name__, key)
|
self.validate_model_manager(manager, self.__name__, key)
|
||||||
add_managers.append((base.__name__, key, manager))
|
add_managers.append((base.__name__, key, manager))
|
||||||
|
|||||||
@@ -135,25 +135,24 @@ class PolymorphicModel(models.Model):
|
|||||||
our appropriate base_objects manager.
|
our appropriate base_objects manager.
|
||||||
"""
|
"""
|
||||||
super(PolymorphicModel, self).__init__(*args, ** kwargs)
|
super(PolymorphicModel, self).__init__(*args, ** kwargs)
|
||||||
|
|
||||||
if self.__class__.polymorphic_super_sub_accessors_replaced: return
|
if self.__class__.polymorphic_super_sub_accessors_replaced: return
|
||||||
self.__class__.polymorphic_super_sub_accessors_replaced = True
|
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):
|
def accessor_function(self):
|
||||||
attr = model.base_objects.get(pk=self.pk)
|
attr = model.base_objects.get(pk=self.pk)
|
||||||
return attr
|
return attr
|
||||||
return accessor_function
|
return accessor_function
|
||||||
|
|
||||||
subclasses_and_superclasses_accessors = self.get_inheritance_relation_fields_and_models()
|
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
|
from django.db.models.fields.related import SingleRelatedObjectDescriptor, ReverseSingleRelatedObjectDescriptor
|
||||||
|
|
||||||
for name,model in subclasses_and_superclasses_accessors.iteritems():
|
for name,model in subclasses_and_superclasses_accessors.iteritems():
|
||||||
orig_accessor = getattr(self.__class__, name, None)
|
orig_accessor = getattr(self.__class__, name, None)
|
||||||
if type(orig_accessor) in [SingleRelatedObjectDescriptor,ReverseSingleRelatedObjectDescriptor]:
|
if type(orig_accessor) in [SingleRelatedObjectDescriptor,ReverseSingleRelatedObjectDescriptor]:
|
||||||
#print 'replacing',name, orig_accessor
|
#print >>sys.stderr, '---------- replacing',name, orig_accessor
|
||||||
setattr(self.__class__, name, property(create_accessor_function_for_model(model)) )
|
setattr(self.__class__, name, property(create_accessor_function_for_model(model, name)) )
|
||||||
|
|
||||||
def get_inheritance_relation_fields_and_models(self):
|
def get_inheritance_relation_fields_and_models(self):
|
||||||
"""helper function for __init__:
|
"""helper function for __init__:
|
||||||
|
|||||||
+70
-12
@@ -4,6 +4,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import settings
|
import settings
|
||||||
|
import sys
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
@@ -29,6 +30,8 @@ class Model2B(Model2A):
|
|||||||
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)
|
||||||
|
class Model2D(Model2C):
|
||||||
|
field4 = models.CharField(max_length=10)
|
||||||
|
|
||||||
class ModelShow1(ShowFieldType,PolymorphicModel):
|
class ModelShow1(ShowFieldType,PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
@@ -84,6 +87,13 @@ class RelationBC(RelationB):
|
|||||||
class RelatingModel(models.Model):
|
class RelatingModel(models.Model):
|
||||||
many2many = models.ManyToManyField(Model2A)
|
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):
|
class MyManager(PolymorphicManager):
|
||||||
def get_query_set(self):
|
def get_query_set(self):
|
||||||
return super(MyManager, self).get_query_set().order_by('-field1')
|
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')
|
entry1 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2')
|
||||||
entry2 = 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": """
|
__test__ = {"doctest": """
|
||||||
#######################################################
|
#######################################################
|
||||||
@@ -249,19 +262,18 @@ __test__ = {"doctest": """
|
|||||||
|
|
||||||
>>> settings.DEBUG=True
|
>>> settings.DEBUG=True
|
||||||
|
|
||||||
#>>> get_version()
|
|
||||||
#'1.0 rc1'
|
|
||||||
|
|
||||||
|
|
||||||
### simple inheritance
|
### simple inheritance
|
||||||
|
|
||||||
>>> o=Model2A.objects.create(field1='A1')
|
>>> o=Model2A.objects.create(field1='A1')
|
||||||
>>> o=Model2B.objects.create(field1='B1', field2='B2')
|
>>> o=Model2B.objects.create(field1='B1', field2='B2')
|
||||||
>>> o=Model2C.objects.create(field1='C1', field2='C2', field3='C3')
|
>>> o=Model2C.objects.create(field1='C1', field2='C2', field3='C3')
|
||||||
|
>>> o=Model2D.objects.create(field1='D1', field2='D2', field3='D3', field4='D4')
|
||||||
[ <Model2A: id 1, field1 (CharField)>,
|
>>> Model2A.objects.all()
|
||||||
|
[ <Model2A: id 1, field1 (CharField)>,
|
||||||
<Model2B: id 2, field1 (CharField), field2 (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()
|
# manual get_real_instance()
|
||||||
>>> o=Model2A.base_objects.get(field1='C1')
|
>>> o=Model2A.base_objects.get(field1='C1')
|
||||||
@@ -269,6 +281,48 @@ __test__ = {"doctest": """
|
|||||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>
|
<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()
|
### ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent, also with annotate()
|
||||||
|
|
||||||
>>> o=ModelShow1.objects.create(field1='abc')
|
>>> o=ModelShow1.objects.create(field1='abc')
|
||||||
@@ -315,15 +369,18 @@ __test__ = {"doctest": """
|
|||||||
|
|
||||||
>>> Model2A.objects.instance_of(Model2B)
|
>>> Model2A.objects.instance_of(Model2B)
|
||||||
[ <Model2B: id 2, field1 (CharField), field2 (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)> ]
|
||||||
|
|
||||||
>>> Model2A.objects.filter(instance_of=Model2B)
|
>>> Model2A.objects.filter(instance_of=Model2B)
|
||||||
[ <Model2B: id 2, field1 (CharField), field2 (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)> ]
|
||||||
|
|
||||||
>>> Model2A.objects.filter(Q(instance_of=Model2B))
|
>>> Model2A.objects.filter(Q(instance_of=Model2B))
|
||||||
[ <Model2B: id 2, field1 (CharField), field2 (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)> ]
|
||||||
|
|
||||||
>>> Model2A.objects.not_instance_of(Model2B)
|
>>> Model2A.objects.not_instance_of(Model2B)
|
||||||
[ <Model2A: id 1, field1 (CharField)> ]
|
[ <Model2A: id 1, field1 (CharField)> ]
|
||||||
@@ -345,7 +402,8 @@ __test__ = {"doctest": """
|
|||||||
>>> oa.delete()
|
>>> oa.delete()
|
||||||
>>> Model2A.objects.all()
|
>>> Model2A.objects.all()
|
||||||
[ <Model2A: id 1, field1 (CharField)>,
|
[ <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
|
### queryset combining
|
||||||
@@ -405,8 +463,8 @@ __test__ = {"doctest": """
|
|||||||
>>> o=ModelWithMyManager.objects.create(field1='D1b', field4='D4b')
|
>>> o=ModelWithMyManager.objects.create(field1='D1b', field4='D4b')
|
||||||
|
|
||||||
>>> ModelWithMyManager.objects.all()
|
>>> ModelWithMyManager.objects.all()
|
||||||
[ <ModelWithMyManager: id 5, field1 (CharField): "D1b", field4 (CharField): "D4b">,
|
[ <ModelWithMyManager: id 6, field1 (CharField): "D1b", field4 (CharField): "D4b">,
|
||||||
<ModelWithMyManager: id 4, field1 (CharField): "D1a", field4 (CharField): "D4a"> ]
|
<ModelWithMyManager: id 5, field1 (CharField): "D1a", field4 (CharField): "D4a"> ]
|
||||||
|
|
||||||
>>> type(ModelWithMyManager.objects)
|
>>> type(ModelWithMyManager.objects)
|
||||||
<class 'polymorphic.tests.MyManager'>
|
<class 'polymorphic.tests.MyManager'>
|
||||||
|
|||||||
Reference in New Issue
Block a user