mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-02 20:54:42 +03:00
Fix broken nested fields
This commit is contained in:
parent
17b77fc446
commit
4058223309
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user