Use parent's primary key when model is derived via multitable inheritance

This commit is contained in:
Mjumbe Wawatu Ukweli 2013-03-11 03:23:44 -04:00
parent 2088023293
commit e7e470739f
3 changed files with 60 additions and 3 deletions

View File

@ -456,8 +456,11 @@ class ModelSerializer(Serializer):
"Serializer class '%s' is missing 'model' Meta option" % self.__class__.__name__ "Serializer class '%s' is missing 'model' Meta option" % self.__class__.__name__
opts = get_concrete_model(cls)._meta opts = get_concrete_model(cls)._meta
pk_field = opts.pk pk_field = opts.pk
# while pk_field.rel:
# pk_field = pk_field.rel.to._meta.pk # If model is a child via multitable inheritance, use parent's pk
while isinstance(pk_field, models.OneToOneField) and pk_field.rel.parent_link:
pk_field = pk_field.rel.to._meta.pk
fields = [pk_field] fields = [pk_field]
fields += [field for field in opts.fields if field.serialize] fields += [field for field in opts.fields if field.serialize]
fields += [field for field in opts.many_to_many if field.serialize] fields += [field for field in opts.many_to_many if field.serialize]

View File

@ -166,3 +166,17 @@ class NullableOneToOneSource(RESTFrameworkModel):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
target = models.OneToOneField(OneToOneTarget, null=True, blank=True, target = models.OneToOneField(OneToOneTarget, null=True, blank=True,
related_name='nullable_source') related_name='nullable_source')
# Inherited
class ParentModel(RESTFrameworkModel):
name1 = models.CharField(max_length=100)
class ChildModel(ParentModel):
name2 = models.CharField(max_length=100)
class AssociatedModel(RESTFrameworkModel):
ref = models.OneToOneField(ParentModel, primary_key=True)
name = models.CharField(max_length=100)

View File

@ -4,7 +4,8 @@ from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel, from rest_framework.tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel,
BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel,
ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo) ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo, ParentModel, ChildModel,
AssociatedModel)
import datetime import datetime
import pickle import pickle
@ -96,6 +97,16 @@ class BrokenModelSerializer(serializers.ModelSerializer):
fields = ['some_field'] fields = ['some_field']
class DerivedModelSerializer(serializers.ModelSerializer):
class Meta:
model = ChildModel
class AssociatedModelSerializer(serializers.ModelSerializer):
class Meta:
model = AssociatedModel
class BasicTests(TestCase): class BasicTests(TestCase):
def setUp(self): def setUp(self):
self.comment = Comment( self.comment = Comment(
@ -170,6 +181,27 @@ class BasicTests(TestCase):
self.assertEqual(set(serializer.data.keys()), self.assertEqual(set(serializer.data.keys()),
set(['name', 'age', 'info'])) set(['name', 'age', 'info']))
def test_multitable_inherited_model_fields_as_expected(self):
"""
Assert that the parent pointer field is not included in the fields
serialized fields
"""
child = ChildModel(name1='parent name', name2='child name')
serializer = DerivedModelSerializer(child)
self.assertEqual(set(serializer.data.keys()),
set(['name1', 'name2', 'id']))
def test_onetoone_primary_key_model_fields_as_expected(self):
"""
Assert that a model with a onetoone field that is the primary key is
not treated like a derived model
"""
parent = ParentModel(name1='parent name')
associate = AssociatedModel(name='hello', ref=parent)
serializer = AssociatedModelSerializer(associate)
self.assertEqual(set(serializer.data.keys()),
set(['name', 'ref']))
def test_field_with_dictionary(self): def test_field_with_dictionary(self):
""" """
Make sure that dictionaries from fields are left intact Make sure that dictionaries from fields are left intact
@ -250,6 +282,14 @@ class ValidationTests(TestCase):
self.assertEqual(serializer.is_valid(), False) self.assertEqual(serializer.is_valid(), False)
self.assertEqual(serializer.errors, {'email': ['This field is required.']}) self.assertEqual(serializer.errors, {'email': ['This field is required.']})
def test_multitable_inherited_model(self):
data = {
'name1': 'parent name',
'name2': 'child name',
}
serializer = DerivedModelSerializer(data=data)
self.assertEqual(serializer.is_valid(), True)
def test_missing_bool_with_default(self): def test_missing_bool_with_default(self):
"""Make sure that a boolean value with a 'False' value is not """Make sure that a boolean value with a 'False' value is not
mistaken for not having a default.""" mistaken for not having a default."""