Fix broken nested fields

This commit is contained in:
Tom Christie 2012-12-11 21:07:25 +00:00
parent 17b77fc446
commit 4058223309
4 changed files with 58 additions and 34 deletions

View File

@ -19,6 +19,16 @@ except ImportError:
import StringIO
# Try to import PIL in either of the two ways it can end up installed.
try:
from PIL import Image
except ImportError:
try:
import Image
except ImportError:
Image = None
def get_concrete_model(model_cls):
try:
return model_cls._meta.concrete_model

View File

@ -1056,11 +1056,8 @@ class ImageField(FileField):
if f is None:
return None
# Try to import PIL in either of the two ways it can end up installed.
try:
from PIL import Image
except ImportError:
import Image
from compat import Image
assert Image is not None, 'PIL must be installed for ImageField support'
# We need to get a file object for PIL. We might have a path or we might
# have to read the data into memory.

View File

@ -237,7 +237,8 @@ class BaseSerializer(Field):
except ValidationError as err:
self._errors[field_name] = self._errors.get(field_name, []) + list(err.messages)
# We don't run .validate() because field-validation failed and thus `attrs` may not be complete.
# If there are already errors, we don't run .validate() because
# field-validation failed and thus `attrs` may not be complete.
# which in turn can cause inconsistent validation errors.
if not self._errors:
try:
@ -299,17 +300,14 @@ class BaseSerializer(Field):
Override default so that we can apply ModelSerializer as a nested
field to relationships.
"""
if self.source:
value = obj
for component in self.source.split('.'):
value = getattr(value, component)
if is_simple_callable(value):
value = value()
obj = value
obj = getattr(obj, component)
if is_simple_callable(obj):
obj = obj()
else:
value = getattr(obj, field_name)
if is_simple_callable(value):
obj = getattr(obj, field_name)
if is_simple_callable(obj):
obj = value()
# If the object has an "all" method, assume it's a relationship
@ -486,15 +484,10 @@ class ModelSerializer(Serializer):
except KeyError:
return ModelField(model_field=model_field, **kwargs)
def validate(self, attrs):
copied_attrs = copy.deepcopy(attrs)
restored_object = self.restore_object(copied_attrs, instance=getattr(self, 'object', None))
self.perform_model_validation(restored_object)
return attrs
def perform_model_validation(self, restored_object):
# Call Django's full_clean() which in turn calls: Model.clean_fields(), Model.clean(), Model.validat_unique()
restored_object.full_clean(exclude=list(self.get_excluded_fieldnames()))
# def validate(self, attrs):
# restored_object = self.restore_object(attrs, instance=getattr(self, 'object', None))
# restored_object.full_clean(exclude=list(self.get_excluded_fieldnames()))
# return attrs
def restore_object(self, attrs, instance=None):
"""
@ -517,7 +510,14 @@ class ModelSerializer(Serializer):
for field in self.opts.model._meta.many_to_many:
if field.name in attrs:
self.m2m_data[field.name] = attrs.pop(field.name)
return self.opts.model(**attrs)
instance = self.opts.model(**attrs)
try:
instance.full_clean(exclude=list(self.get_excluded_fieldnames()))
except ValidationError, err:
self._errors = err.message_dict
return None
return instance
def save(self, save_m2m=True):
"""

View File

@ -1,4 +1,5 @@
import datetime, pickle
import datetime
import pickle
from django.test import TestCase
from rest_framework import serializers
from rest_framework.tests.models import (Album, ActionItem, Anchor, BasicModel,
@ -727,15 +728,11 @@ class SerializerPickleTests(TestCase):
fields = ('name', 'age')
pickle.dumps(InnerPersonSerializer(Person(name="Noah", age=950)).data)
class DepthTest(TestCase):
def test_depth(self):
user = Person.objects.create(name="django",age=1)
post = BlogPost.objects.create(title="Test blog post", writer=user)
class PersonSerializer(serializers.ModelSerializer):
class Meta:
model = Person
fields = ("name", "age")
class DepthTest(TestCase):
def test_implicit_nesting(self):
writer = Person.objects.create(name="django", age=1)
post = BlogPost.objects.create(title="Test blog post", writer=writer)
class BlogPostSerializer(serializers.ModelSerializer):
class Meta:
@ -744,6 +741,26 @@ class DepthTest(TestCase):
serializer = BlogPostSerializer(instance=post)
expected = {'id': 1, 'title': u'Test blog post',
'writer': {'id': 1, 'name': u'django', 'age':1}}
'writer': {'id': 1, 'name': u'django', 'age': 1}}
self.assertEqual(serializer.data, expected)
def test_explicit_nesting(self):
writer = Person.objects.create(name="django", age=1)
post = BlogPost.objects.create(title="Test blog post", writer=writer)
class PersonSerializer(serializers.ModelSerializer):
class Meta:
model = Person
class BlogPostSerializer(serializers.ModelSerializer):
writer = PersonSerializer()
class Meta:
model = BlogPost
serializer = BlogPostSerializer(instance=post)
expected = {'id': 1, 'title': u'Test blog post',
'writer': {'id': 1, 'name': u'django', 'age': 1}}
self.assertEqual(serializer.data, expected)