diff options
Diffstat (limited to 'rest_framework')
| -rw-r--r-- | rest_framework/compat.py | 10 | ||||
| -rw-r--r-- | rest_framework/fields.py | 7 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 38 | ||||
| -rw-r--r-- | rest_framework/tests/serializer.py | 31 |
4 files changed, 55 insertions, 31 deletions
diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 09b76368..d4901437 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -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 diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 82745973..75ce1b9f 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -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. diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index c3f260c7..ebeb43e8 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -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): """ diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index f80762f0..50a5f5a4 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -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,23 +728,39 @@ 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) + 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: + model = BlogPost + depth = 1 + + 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) + + 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 - fields = ("name", "age") class BlogPostSerializer(serializers.ModelSerializer): + writer = PersonSerializer() + class Meta: model = BlogPost - depth = 1 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) |
