diff options
| author | BrickXu | 2014-12-05 13:30:56 +0800 | 
|---|---|---|
| committer | BrickXu | 2014-12-05 13:30:56 +0800 | 
| commit | 4042180392fb7809d1c8d2f6ca0bc6e18c114e6c (patch) | |
| tree | 5fab017db281948eecf54d9dd8d5f0a8b323fa77 /rest_framework | |
| parent | 81870b6e1a7b0c3c149d4bfba0e20924ebf1b187 (diff) | |
| parent | e8cbf41bd9066a21bf102bb60fbb42b4b15e05f6 (diff) | |
| download | django-rest-framework-4042180392fb7809d1c8d2f6ca0bc6e18c114e6c.tar.bz2 | |
Merge pull request #3 from tomchristie/master
Merge upstream
Diffstat (limited to 'rest_framework')
| -rw-r--r-- | rest_framework/parsers.py | 13 | ||||
| -rw-r--r-- | rest_framework/renderers.py | 4 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 53 | ||||
| -rw-r--r-- | rest_framework/utils/serializer_helpers.py | 14 | ||||
| -rw-r--r-- | rest_framework/viewsets.py | 6 | 
5 files changed, 62 insertions, 28 deletions
| diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py index ccb82f03..d229abec 100644 --- a/rest_framework/parsers.py +++ b/rest_framework/parsers.py @@ -256,23 +256,24 @@ class FileUploadParser(BaseParser):          chunks = ChunkIter(stream, chunk_size)          counters = [0] * len(upload_handlers) -        for handler in upload_handlers: +        for index, handler in enumerate(upload_handlers):              try:                  handler.new_file(None, filename, content_type,                                   content_length, encoding)              except StopFutureHandlers: +                upload_handlers = upload_handlers[:index + 1]                  break          for chunk in chunks: -            for i, handler in enumerate(upload_handlers): +            for index, handler in enumerate(upload_handlers):                  chunk_length = len(chunk) -                chunk = handler.receive_data_chunk(chunk, counters[i]) -                counters[i] += chunk_length +                chunk = handler.receive_data_chunk(chunk, counters[index]) +                counters[index] += chunk_length                  if chunk is None:                      break -        for i, handler in enumerate(upload_handlers): -            file_obj = handler.file_complete(counters[i]) +        for index, handler in enumerate(upload_handlers): +            file_obj = handler.file_complete(counters[index])              if file_obj:                  return DataAndFiles(None, {'file': file_obj})          raise ParseError("FileUpload parse error - " diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index e87d16d0..31d3ef5f 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -374,6 +374,10 @@ class HTMLFormRenderer(BaseRenderer):              'base_template': 'input.html',              'input_type': 'time'          }, +        serializers.FileField: { +            'base_template': 'input.html', +            'input_type': 'file' +        },          serializers.BooleanField: {              'base_template': 'checkbox.html'          }, diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 0d0a4d9a..af8aeb48 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -127,6 +127,14 @@ class BaseSerializer(Field):              (self.__class__.__module__, self.__class__.__name__)          ) +        assert hasattr(self, '_errors'), ( +            'You must call `.is_valid()` before calling `.save()`.' +        ) + +        assert not self.errors, ( +            'You cannot call `.save()` on a serializer with invalid data.' +        ) +          validated_data = dict(              list(self.validated_data.items()) +              list(kwargs.items()) @@ -600,20 +608,20 @@ class ModelSerializer(Serializer):      })      _related_class = PrimaryKeyRelatedField -    def create(self, validated_attrs): +    def create(self, validated_data):          """          We have a bit of extra checking around this in order to provide          descriptive messages when something goes wrong, but this method is          essentially just: -            return ExampleModel.objects.create(**validated_attrs) +            return ExampleModel.objects.create(**validated_data)          If there are many to many fields present on the instance then they          cannot be set until the model is instantiated, in which case the          implementation is like so: -            example_relationship = validated_attrs.pop('example_relationship') -            instance = ExampleModel.objects.create(**validated_attrs) +            example_relationship = validated_data.pop('example_relationship') +            instance = ExampleModel.objects.create(**validated_data)              instance.example_relationship = example_relationship              return instance @@ -625,8 +633,8 @@ class ModelSerializer(Serializer):          # If we don't do this explicitly they'd likely get a confusing          # error at the point of calling `Model.objects.create()`.          assert not any( -            isinstance(field, BaseSerializer) and not field.read_only -            for field in self.fields.values() +            isinstance(field, BaseSerializer) and (key in validated_attrs) +            for key, field in self.fields.items()          ), (              'The `.create()` method does not suport nested writable fields '              'by default. Write an explicit `.create()` method for serializer ' @@ -636,16 +644,33 @@ class ModelSerializer(Serializer):          ModelClass = self.Meta.model -        # Remove many-to-many relationships from validated_attrs. +        # Remove many-to-many relationships from validated_data.          # They are not valid arguments to the default `.create()` method,          # as they require that the instance has already been saved.          info = model_meta.get_field_info(ModelClass)          many_to_many = {}          for field_name, relation_info in info.relations.items(): -            if relation_info.to_many and (field_name in validated_attrs): -                many_to_many[field_name] = validated_attrs.pop(field_name) +            if relation_info.to_many and (field_name in validated_data): +                many_to_many[field_name] = validated_data.pop(field_name) -        instance = ModelClass.objects.create(**validated_attrs) +        try: +            instance = ModelClass.objects.create(**validated_data) +        except TypeError as exc: +            msg = ( +                'Got a `TypeError` when calling `%s.objects.create()`. ' +                'This may be because you have a writable field on the ' +                'serializer class that is not a valid argument to ' +                '`%s.objects.create()`. You may need to make the field ' +                'read-only, or override the %s.create() method to handle ' +                'this correctly.\nOriginal exception text was: %s.' % +                ( +                    ModelClass.__name__, +                    ModelClass.__name__, +                    self.__class__.__name__, +                    exc +                ) +            ) +            raise TypeError(msg)          # Save many-to-many relationships after the instance is created.          if many_to_many: @@ -654,10 +679,10 @@ class ModelSerializer(Serializer):          return instance -    def update(self, instance, validated_attrs): +    def update(self, instance, validated_data):          assert not any( -            isinstance(field, BaseSerializer) and not field.read_only -            for field in self.fields.values() +            isinstance(field, BaseSerializer) and (key in validated_attrs) +            for key, field in self.fields.items()          ), (              'The `.update()` method does not suport nested writable fields '              'by default. Write an explicit `.update()` method for serializer ' @@ -665,7 +690,7 @@ class ModelSerializer(Serializer):              (self.__class__.__module__, self.__class__.__name__)          ) -        for attr, value in validated_attrs.items(): +        for attr, value in validated_data.items():              setattr(instance, attr, value)          instance.save()          return instance diff --git a/rest_framework/utils/serializer_helpers.py b/rest_framework/utils/serializer_helpers.py index 92d19857..277cf649 100644 --- a/rest_framework/utils/serializer_helpers.py +++ b/rest_framework/utils/serializer_helpers.py @@ -1,3 +1,4 @@ +import collections  from rest_framework.compat import OrderedDict @@ -70,7 +71,7 @@ class NestedBoundField(BoundField):          return BoundField(field, value, error, prefix=self.name + '.') -class BindingDict(object): +class BindingDict(collections.MutableMapping):      """      This dict-like object is used to store fields on a serializer. @@ -92,11 +93,8 @@ class BindingDict(object):      def __delitem__(self, key):          del self.fields[key] -    def items(self): -        return self.fields.items() - -    def keys(self): -        return self.fields.keys() +    def __iter__(self): +        return iter(self.fields) -    def values(self): -        return self.fields.values() +    def __len__(self): +        return len(self.fields) diff --git a/rest_framework/viewsets.py b/rest_framework/viewsets.py index 84b4bd8d..70d14695 100644 --- a/rest_framework/viewsets.py +++ b/rest_framework/viewsets.py @@ -48,6 +48,12 @@ class ViewSetMixin(object):          # eg. 'List' or 'Instance'.          cls.suffix = None +        # actions must not be empty +        if not actions: +            raise TypeError("The `actions` argument must be provided when " +                            "calling `.as_view()` on a ViewSet. For example " +                            "`.as_view({'get': 'list'})`") +          # sanitize keyword arguments          for key in initkwargs:              if key in cls.http_method_names: | 
