mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-10 00:21:01 +03:00
Fix broken nested fields
This commit is contained in:
parent
17b77fc446
commit
4058223309
|
@ -19,6 +19,16 @@ except ImportError:
|
||||||
import StringIO
|
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):
|
def get_concrete_model(model_cls):
|
||||||
try:
|
try:
|
||||||
return model_cls._meta.concrete_model
|
return model_cls._meta.concrete_model
|
||||||
|
|
|
@ -1056,11 +1056,8 @@ class ImageField(FileField):
|
||||||
if f is None:
|
if f is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Try to import PIL in either of the two ways it can end up installed.
|
from compat import Image
|
||||||
try:
|
assert Image is not None, 'PIL must be installed for ImageField support'
|
||||||
from PIL import Image
|
|
||||||
except ImportError:
|
|
||||||
import Image
|
|
||||||
|
|
||||||
# We need to get a file object for PIL. We might have a path or we might
|
# We need to get a file object for PIL. We might have a path or we might
|
||||||
# have to read the data into memory.
|
# have to read the data into memory.
|
||||||
|
|
|
@ -237,7 +237,8 @@ class BaseSerializer(Field):
|
||||||
except ValidationError as err:
|
except ValidationError as err:
|
||||||
self._errors[field_name] = self._errors.get(field_name, []) + list(err.messages)
|
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.
|
# which in turn can cause inconsistent validation errors.
|
||||||
if not self._errors:
|
if not self._errors:
|
||||||
try:
|
try:
|
||||||
|
@ -299,17 +300,14 @@ class BaseSerializer(Field):
|
||||||
Override default so that we can apply ModelSerializer as a nested
|
Override default so that we can apply ModelSerializer as a nested
|
||||||
field to relationships.
|
field to relationships.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.source:
|
if self.source:
|
||||||
value = obj
|
|
||||||
for component in self.source.split('.'):
|
for component in self.source.split('.'):
|
||||||
value = getattr(value, component)
|
obj = getattr(obj, component)
|
||||||
if is_simple_callable(value):
|
if is_simple_callable(obj):
|
||||||
value = value()
|
obj = obj()
|
||||||
obj = value
|
|
||||||
else:
|
else:
|
||||||
value = getattr(obj, field_name)
|
obj = getattr(obj, field_name)
|
||||||
if is_simple_callable(value):
|
if is_simple_callable(obj):
|
||||||
obj = value()
|
obj = value()
|
||||||
|
|
||||||
# If the object has an "all" method, assume it's a relationship
|
# If the object has an "all" method, assume it's a relationship
|
||||||
|
@ -486,15 +484,10 @@ class ModelSerializer(Serializer):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return ModelField(model_field=model_field, **kwargs)
|
return ModelField(model_field=model_field, **kwargs)
|
||||||
|
|
||||||
def validate(self, attrs):
|
# def validate(self, attrs):
|
||||||
copied_attrs = copy.deepcopy(attrs)
|
# restored_object = self.restore_object(attrs, instance=getattr(self, 'object', None))
|
||||||
restored_object = self.restore_object(copied_attrs, instance=getattr(self, 'object', None))
|
# restored_object.full_clean(exclude=list(self.get_excluded_fieldnames()))
|
||||||
self.perform_model_validation(restored_object)
|
# return attrs
|
||||||
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 restore_object(self, attrs, instance=None):
|
def restore_object(self, attrs, instance=None):
|
||||||
"""
|
"""
|
||||||
|
@ -517,7 +510,14 @@ class ModelSerializer(Serializer):
|
||||||
for field in self.opts.model._meta.many_to_many:
|
for field in self.opts.model._meta.many_to_many:
|
||||||
if field.name in attrs:
|
if field.name in attrs:
|
||||||
self.m2m_data[field.name] = attrs.pop(field.name)
|
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):
|
def save(self, save_m2m=True):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import datetime, pickle
|
import datetime
|
||||||
|
import pickle
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.tests.models import (Album, ActionItem, Anchor, BasicModel,
|
from rest_framework.tests.models import (Album, ActionItem, Anchor, BasicModel,
|
||||||
|
@ -727,15 +728,11 @@ class SerializerPickleTests(TestCase):
|
||||||
fields = ('name', 'age')
|
fields = ('name', 'age')
|
||||||
pickle.dumps(InnerPersonSerializer(Person(name="Noah", age=950)).data)
|
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 DepthTest(TestCase):
|
||||||
class Meta:
|
def test_implicit_nesting(self):
|
||||||
model = Person
|
writer = Person.objects.create(name="django", age=1)
|
||||||
fields = ("name", "age")
|
post = BlogPost.objects.create(title="Test blog post", writer=writer)
|
||||||
|
|
||||||
class BlogPostSerializer(serializers.ModelSerializer):
|
class BlogPostSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -744,6 +741,26 @@ class DepthTest(TestCase):
|
||||||
|
|
||||||
serializer = BlogPostSerializer(instance=post)
|
serializer = BlogPostSerializer(instance=post)
|
||||||
expected = {'id': 1, 'title': u'Test blog 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)
|
self.assertEqual(serializer.data, expected)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user