Merge pull request #365 from ghost/fix/37-subclass-selector-on-abstract-proxy-models
#37: Fix model subclass ___ selector for abstract/proxy modelsfix_request_path_info
commit
ec3fb34f08
|
|
@ -16,3 +16,4 @@ build/
|
||||||
dist/
|
dist/
|
||||||
docs/_build/
|
docs/_build/
|
||||||
htmlcov/
|
htmlcov/
|
||||||
|
venv/
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,8 @@ def translate_polymorphic_field_path(queryset_model, field_path):
|
||||||
return myclass.__name__.lower()
|
return myclass.__name__.lower()
|
||||||
path = _create_base_path(baseclass, b)
|
path = _create_base_path(baseclass, b)
|
||||||
if path:
|
if path:
|
||||||
|
if b._meta.abstract or b._meta.proxy:
|
||||||
|
return myclass.__name__.lower()
|
||||||
return path + '__' + myclass.__name__.lower()
|
return path + '__' + myclass.__name__.lower()
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1130,4 +1130,66 @@ class Migration(migrations.Migration):
|
||||||
},
|
},
|
||||||
bases=('tests.duck',),
|
bases=('tests.duck',),
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SubclassSelectorAbstractBaseModel',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('base_field', models.CharField(default='test_bf', max_length=10)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
'base_manager_name': 'objects',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SubclassSelectorProxyBaseModel',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('base_field', models.CharField(default='test_bf', max_length=10)),
|
||||||
|
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.subclassselectorproxybasemodel_set+', to='contenttypes.ContentType')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
'base_manager_name': 'objects',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SubclassSelectorAbstractConcreteModel',
|
||||||
|
fields=[
|
||||||
|
('subclassselectorabstractbasemodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.SubclassSelectorAbstractBaseModel')),
|
||||||
|
('abstract_field', models.CharField(default='test_af', max_length=10)),
|
||||||
|
('concrete_field', models.CharField(default='test_cf', max_length=10)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
bases=('tests.subclassselectorabstractbasemodel',),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subclassselectorabstractbasemodel',
|
||||||
|
name='polymorphic_ctype',
|
||||||
|
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_tests.subclassselectorabstractbasemodel_set+', to='contenttypes.ContentType'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SubclassSelectorProxyModel',
|
||||||
|
fields=[
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'proxy': True,
|
||||||
|
'indexes': [],
|
||||||
|
},
|
||||||
|
bases=('tests.subclassselectorproxybasemodel',),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SubclassSelectorProxyConcreteModel',
|
||||||
|
fields=[
|
||||||
|
('subclassselectorproxybasemodel_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.SubclassSelectorProxyBaseModel')),
|
||||||
|
('concrete_field', models.CharField(default='test_cf', max_length=10)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
'base_manager_name': 'objects',
|
||||||
|
},
|
||||||
|
bases=('tests.subclassselectorproxymodel',),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -450,3 +450,31 @@ class MultiTableBase(PolymorphicModel):
|
||||||
|
|
||||||
class MultiTableDerived(MultiTableBase):
|
class MultiTableDerived(MultiTableBase):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
|
class SubclassSelectorAbstractBaseModel(PolymorphicModel):
|
||||||
|
base_field = models.CharField(max_length=10, default='test_bf')
|
||||||
|
|
||||||
|
|
||||||
|
class SubclassSelectorAbstractModel(SubclassSelectorAbstractBaseModel):
|
||||||
|
abstract_field = models.CharField(max_length=10, default='test_af')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
|
class SubclassSelectorAbstractConcreteModel(SubclassSelectorAbstractModel):
|
||||||
|
concrete_field = models.CharField(max_length=10, default='test_cf')
|
||||||
|
|
||||||
|
|
||||||
|
class SubclassSelectorProxyBaseModel(PolymorphicModel):
|
||||||
|
base_field = models.CharField(max_length=10, default='test_bf')
|
||||||
|
|
||||||
|
|
||||||
|
class SubclassSelectorProxyModel(SubclassSelectorProxyBaseModel):
|
||||||
|
class Meta:
|
||||||
|
proxy = True
|
||||||
|
|
||||||
|
|
||||||
|
class SubclassSelectorProxyConcreteModel(SubclassSelectorProxyModel):
|
||||||
|
concrete_field = models.CharField(max_length=10, default='test_cf')
|
||||||
|
|
@ -74,6 +74,10 @@ from polymorphic.tests.models import (
|
||||||
RelationBC,
|
RelationBC,
|
||||||
RelationBase,
|
RelationBase,
|
||||||
RubberDuck,
|
RubberDuck,
|
||||||
|
SubclassSelectorAbstractBaseModel,
|
||||||
|
SubclassSelectorAbstractConcreteModel,
|
||||||
|
SubclassSelectorProxyBaseModel,
|
||||||
|
SubclassSelectorProxyConcreteModel,
|
||||||
TestParentLinkAndRelatedName,
|
TestParentLinkAndRelatedName,
|
||||||
UUIDArtProject,
|
UUIDArtProject,
|
||||||
UUIDPlainA,
|
UUIDPlainA,
|
||||||
|
|
@ -859,21 +863,21 @@ class PolymorphicTests(TransactionTestCase):
|
||||||
self.assertEqual(ProxyModelB.objects.model, ProxyModelB)
|
self.assertEqual(ProxyModelB.objects.model, ProxyModelB)
|
||||||
|
|
||||||
# Create objects
|
# Create objects
|
||||||
ProxyModelA.objects.create(name="object1")
|
object1_pk = ProxyModelA.objects.create(name="object1").pk
|
||||||
ProxyModelB.objects.create(name="object2", field2="bb")
|
object2_pk = ProxyModelB.objects.create(name="object2", field2="bb").pk
|
||||||
|
|
||||||
# Getting single objects
|
# Getting single objects
|
||||||
object1 = ProxyModelBase.objects.get(name='object1')
|
object1 = ProxyModelBase.objects.get(name='object1')
|
||||||
object2 = ProxyModelBase.objects.get(name='object2')
|
object2 = ProxyModelBase.objects.get(name='object2')
|
||||||
self.assertEqual(repr(object1), '<ProxyModelA: id 1, name (CharField) "object1", field1 (CharField) "">')
|
self.assertEqual(repr(object1), '<ProxyModelA: id %i, name (CharField) "object1", field1 (CharField) "">' % object1_pk)
|
||||||
self.assertEqual(repr(object2), '<ProxyModelB: id 2, name (CharField) "object2", field2 (CharField) "bb">')
|
self.assertEqual(repr(object2), '<ProxyModelB: id %i, name (CharField) "object2", field2 (CharField) "bb">' % object2_pk)
|
||||||
self.assertIsInstance(object1, ProxyModelA)
|
self.assertIsInstance(object1, ProxyModelA)
|
||||||
self.assertIsInstance(object2, ProxyModelB)
|
self.assertIsInstance(object2, ProxyModelB)
|
||||||
|
|
||||||
# Same for lists
|
# Same for lists
|
||||||
objects = list(ProxyModelBase.objects.all().order_by('name'))
|
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[0]), '<ProxyModelA: id %i, name (CharField) "object1", field1 (CharField) "">' % object1_pk)
|
||||||
self.assertEqual(repr(objects[1]), '<ProxyModelB: id 2, name (CharField) "object2", field2 (CharField) "bb">')
|
self.assertEqual(repr(objects[1]), '<ProxyModelB: id %i, name (CharField) "object2", field2 (CharField) "bb">' % object2_pk)
|
||||||
self.assertIsInstance(objects[0], ProxyModelA)
|
self.assertIsInstance(objects[0], ProxyModelA)
|
||||||
self.assertIsInstance(objects[1], ProxyModelB)
|
self.assertIsInstance(objects[1], ProxyModelB)
|
||||||
|
|
||||||
|
|
@ -1024,3 +1028,21 @@ class PolymorphicTests(TransactionTestCase):
|
||||||
MultiTableDerived.objects.bulk_create([
|
MultiTableDerived.objects.bulk_create([
|
||||||
MultiTableDerived(field1='field1', field2='field2')
|
MultiTableDerived(field1='field1', field2='field2')
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_can_query_using_subclass_selector_on_abstract_model(self):
|
||||||
|
obj = SubclassSelectorAbstractConcreteModel.objects.create(concrete_field='abc')
|
||||||
|
|
||||||
|
queried_obj = SubclassSelectorAbstractBaseModel.objects.filter(
|
||||||
|
SubclassSelectorAbstractConcreteModel___concrete_field='abc'
|
||||||
|
).get()
|
||||||
|
|
||||||
|
self.assertEqual(obj.pk, queried_obj.pk)
|
||||||
|
|
||||||
|
def test_can_query_using_subclass_selector_on_proxy_model(self):
|
||||||
|
obj = SubclassSelectorProxyConcreteModel.objects.create(concrete_field='abc')
|
||||||
|
|
||||||
|
queried_obj = SubclassSelectorProxyBaseModel.objects.filter(
|
||||||
|
SubclassSelectorProxyConcreteModel___concrete_field='abc'
|
||||||
|
).get()
|
||||||
|
|
||||||
|
self.assertEqual(obj.pk, queried_obj.pk)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue