Merge pull request #31 from vdboor/django15
Fix Django 1.5 (proxy models broke polymorphism)fix_request_path_info
commit
38a230891c
|
|
@ -16,6 +16,11 @@ from query import PolymorphicQuerySet
|
|||
# These are forbidden as field names (a descriptive exception is raised)
|
||||
POLYMORPHIC_SPECIAL_Q_KWORDS = ['instance_of', 'not_instance_of']
|
||||
|
||||
try:
|
||||
from django.db.models.manager import AbstractManagerDescriptor # Django 1.5
|
||||
except ImportError:
|
||||
AbstractManagerDescriptor = None
|
||||
|
||||
|
||||
###################################################################################
|
||||
### PolymorphicModel meta class
|
||||
|
|
@ -91,6 +96,7 @@ class PolymorphicModelBase(ModelBase):
|
|||
use correct mro, only use managers with _inherited==False (they are of no use),
|
||||
skip managers that are overwritten by the user with same-named class attributes (in attrs)
|
||||
"""
|
||||
#print "** ", self.__name__
|
||||
add_managers = []
|
||||
add_managers_keys = set()
|
||||
for base in self.__mro__[1:]:
|
||||
|
|
@ -102,9 +108,23 @@ class PolymorphicModelBase(ModelBase):
|
|||
for key, manager in base.__dict__.items():
|
||||
if type(manager) == models.manager.ManagerDescriptor:
|
||||
manager = manager.manager
|
||||
|
||||
if AbstractManagerDescriptor is not None:
|
||||
# Django 1.4 unconditionally assigned managers to a model. As of Django 1.5 however,
|
||||
# the abstract models don't get any managers, only a AbstractManagerDescriptor as substitute.
|
||||
# Pretend that the manager is still there, so all code works like it used to.
|
||||
if type(manager) == AbstractManagerDescriptor and base.__name__ == 'PolymorphicModel':
|
||||
model = manager.model
|
||||
if key == 'objects':
|
||||
manager = PolymorphicManager()
|
||||
manager.model = model
|
||||
elif key == 'base_objects':
|
||||
manager = models.Manager()
|
||||
manager.model = model
|
||||
|
||||
if not isinstance(manager, models.Manager):
|
||||
continue
|
||||
if key in ['_base_manager']:
|
||||
if key == '_base_manager':
|
||||
continue # let Django handle _base_manager
|
||||
if key in attrs:
|
||||
continue
|
||||
|
|
@ -112,7 +132,8 @@ class PolymorphicModelBase(ModelBase):
|
|||
continue # manager with that name already added, skip
|
||||
if manager._inherited:
|
||||
continue # inherited managers (on the bases) have no significance, they are just copies
|
||||
#print >>sys.stderr,'##',self.__name__, key
|
||||
#print '## {0} {1}'.format(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))
|
||||
|
|
@ -121,16 +142,18 @@ class PolymorphicModelBase(ModelBase):
|
|||
|
||||
@classmethod
|
||||
def get_first_user_defined_manager(self):
|
||||
# See if there is a manager attribute directly stored at this inheritance level.
|
||||
mgr_list = []
|
||||
for key, val in self.__dict__.items():
|
||||
item = getattr(self, key)
|
||||
if not isinstance(item, models.Manager): continue
|
||||
mgr_list.append((item.creation_counter, key, item))
|
||||
|
||||
# if there are user defined managers, use first one as _default_manager
|
||||
if mgr_list:
|
||||
_, manager_name, manager = sorted(mgr_list)[0]
|
||||
#sys.stderr.write( '\n# first user defined manager for model "{model}":\n# "{mgrname}": {mgr}\n# manager model: {mgrmodel}\n\n'
|
||||
# .format( model=model_name, mgrname=manager_name, mgr=manager, mgrmodel=manager.model ) )
|
||||
# .format( model=self.__name__, mgrname=manager_name, mgr=manager, mgrmodel=manager.model ) )
|
||||
return manager
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ class PolymorphicModel(models.Model):
|
|||
# some applications want to know the name of the fields that are added to its models
|
||||
polymorphic_internal_model_fields = ['polymorphic_ctype']
|
||||
|
||||
# Note that Django 1.5 removes these managers because the model is abstract.
|
||||
# They are pretended to be there by the metaclass in PolymorphicModelBase.get_inherited_managers()
|
||||
objects = PolymorphicManager()
|
||||
base_objects = models.Manager()
|
||||
|
||||
|
|
|
|||
|
|
@ -178,6 +178,17 @@ class UUIDPlainB(UUIDPlainA):
|
|||
class UUIDPlainC(UUIDPlainB):
|
||||
field3 = models.CharField(max_length=10)
|
||||
|
||||
# base -> proxy -> real models
|
||||
class ProxiedBase(ShowFieldTypeAndContent, PolymorphicModel):
|
||||
name = models.CharField(max_length=10)
|
||||
class ProxyModelBase(ProxiedBase):
|
||||
class Meta:
|
||||
proxy = True
|
||||
class ProxyModelA(ProxyModelBase):
|
||||
field1 = models.CharField(max_length=10)
|
||||
class ProxyModelB(ProxyModelBase):
|
||||
field2 = models.CharField(max_length=10)
|
||||
|
||||
|
||||
# test bad field name
|
||||
#class TestBadFieldModel(ShowFieldType, PolymorphicModel):
|
||||
|
|
@ -194,7 +205,6 @@ class PolymorphicTests(TestCase):
|
|||
"""
|
||||
The test suite
|
||||
"""
|
||||
|
||||
def test_diamond_inheritance(self):
|
||||
# Django diamond problem
|
||||
o1 = DiamondXY.objects.create(field_b='b', field_x='x', field_y='y')
|
||||
|
|
@ -613,6 +623,37 @@ class PolymorphicTests(TestCase):
|
|||
self.assertEqual(repr(type(MROBase2._default_manager)), "<class 'polymorphic.manager.PolymorphicManager'>")
|
||||
|
||||
|
||||
def test_proxy_model_inheritance(self):
|
||||
"""
|
||||
Polymorphic abilities should also work when the base model is a proxy object.
|
||||
"""
|
||||
# The managers should point to the proper objects.
|
||||
# otherwise, the whole excersise is pointless.
|
||||
self.assertEqual(ProxiedBase.objects.model, ProxiedBase)
|
||||
self.assertEqual(ProxyModelBase.objects.model, ProxyModelBase)
|
||||
self.assertEqual(ProxyModelA.objects.model, ProxyModelA)
|
||||
self.assertEqual(ProxyModelB.objects.model, ProxyModelB)
|
||||
|
||||
# Create objects
|
||||
ProxyModelA.objects.create(name="object1")
|
||||
ProxyModelB.objects.create(name="object2", field2="bb")
|
||||
|
||||
# Getting single objects
|
||||
object1 = ProxyModelBase.objects.get(name='object1')
|
||||
object2 = ProxyModelBase.objects.get(name='object2')
|
||||
self.assertEqual(repr(object1), '<ProxyModelA: id 1, name (CharField) "object1", field1 (CharField) "">')
|
||||
self.assertEqual(repr(object2), '<ProxyModelB: id 2, name (CharField) "object2", field2 (CharField) "bb">')
|
||||
self.assertIsInstance(object1, ProxyModelA)
|
||||
self.assertIsInstance(object2, ProxyModelB)
|
||||
|
||||
# Same for lists
|
||||
objects = list(ProxyModelBase.objects.all().order_by('name'))
|
||||
self.assertEqual(repr(objects[0]), '<ProxyModelA: id 1, name (CharField) "object1", field1 (CharField) "">')
|
||||
self.assertEqual(repr(objects[1]), '<ProxyModelB: id 2, name (CharField) "object2", field2 (CharField) "bb">')
|
||||
self.assertIsInstance(objects[0], ProxyModelA)
|
||||
self.assertIsInstance(objects[1], ProxyModelB)
|
||||
|
||||
|
||||
def test_fix_getattribute(self):
|
||||
### fixed issue in PolymorphicModel.__getattribute__: field name same as model name
|
||||
o = ModelFieldNameTest.objects.create(modelfieldnametest='1')
|
||||
|
|
|
|||
Loading…
Reference in New Issue