diff options
| -rw-r--r-- | docs/index.md | 2 | ||||
| -rw-r--r-- | docs/tutorial/1-serialization.md | 24 | ||||
| -rw-r--r-- | docs/tutorial/quickstart.md | 3 | ||||
| -rw-r--r-- | rest_framework/renderers.py | 4 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 28 | ||||
| -rw-r--r-- | rest_framework/viewsets.py | 6 | ||||
| -rw-r--r-- | tests/test_viewsets.py | 35 | 
7 files changed, 73 insertions, 29 deletions
| diff --git a/docs/index.md b/docs/index.md index e0ba2332..52e42fc9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,7 +4,7 @@  <a href="https://twitter.com/share" class="twitter-share-button" data-url="django-rest-framework.org" data-text="Checking out the totally awesome Django REST framework! http://www.django-rest-framework.org" data-count="none"></a>  <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="http://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script> -<img src="https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=master" class="travis-build-image"> +<img src="https://secure.travis-ci.org/tomchristie/django-rest-framework.svg?branch=master" class="travis-build-image">  </p>  --- diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index a3c19858..eb0a00c0 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -101,7 +101,7 @@ The first thing we need to get started on our Web API is to provide a way of ser      class SnippetSerializer(serializers.Serializer):          pk = serializers.IntegerField(read_only=True) -        title = serializers.CharField(required=False, +        title = serializers.CharField(required=False, allow_blank=True                                        max_length=100)          code = serializers.CharField(style={'type': 'textarea'})          linenos = serializers.BooleanField(required=False) @@ -110,21 +110,21 @@ The first thing we need to get started on our Web API is to provide a way of ser          style = serializers.ChoiceField(choices=STYLE_CHOICES,                                          default='friendly') -        def create(self, validated_attrs): +        def create(self, validated_data):              """              Create and return a new `Snippet` instance, given the validated data.              """ -            return Snippet.objects.create(**validated_attrs) +            return Snippet.objects.create(**validated_data) -        def update(self, instance, validated_attrs): +        def update(self, instance, validated_data):              """              Update and return an existing `Snippet` instance, given the validated data.              """ -            instance.title = validated_attrs.get('title', instance.title) -            instance.code = validated_attrs.get('code', instance.code) -            instance.linenos = validated_attrs.get('linenos', instance.linenos) -            instance.language = validated_attrs.get('language', instance.language) -            instance.style = validated_attrs.get('style', instance.style) +            instance.title = validated_data.get('title', instance.title) +            instance.code = validated_data.get('code', instance.code) +            instance.linenos = validated_data.get('linenos', instance.linenos) +            instance.language = validated_data.get('language', instance.language) +            instance.style = validated_data.get('style', instance.style)              instance.save()              return instance @@ -181,7 +181,7 @@ Deserialization is similar.  First we parse a stream into Python native datatype      serializer = SnippetSerializer(data=data)      serializer.is_valid()      # True -    serializer.object +    serializer.save()      # <Snippet: Snippet object>  Notice how similar the API is to working with forms.  The similarity should become even more apparent when we start writing views that use our serializer. @@ -210,7 +210,7 @@ One nice property that serializers have is that you can inspect all the fields i      >>> from snippets.serializers import SnippetSerializer      >>> serializer = SnippetSerializer() -    >>> print repr(serializer)  # In python 3 use `print(repr(serializer))` +    >>> print(repr(serializer))      SnippetSerializer():          id = IntegerField(label='ID', read_only=True)          title = CharField(allow_blank=True, max_length=100, required=False) @@ -301,7 +301,7 @@ We'll also need a view which corresponds to an individual snippet, and can be us  Finally we need to wire these views up.  Create the `snippets/urls.py` file: -    from django.conf.urls import patterns, url +    from django.conf.urls import url      from snippets import views      urlpatterns = [ diff --git a/docs/tutorial/quickstart.md b/docs/tutorial/quickstart.md index 3e1ce0a9..d0703381 100644 --- a/docs/tutorial/quickstart.md +++ b/docs/tutorial/quickstart.md @@ -19,10 +19,9 @@ Create a new Django project named `tutorial`, then start a new app called `quick      pip install djangorestframework      # Set up a new project with a single application -    django-admin.py startproject tutorial +    django-admin.py startproject tutorial .      cd tutorial      django-admin.py startapp quickstart -	cd ..  Now sync your database for the first time: diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 64ad5a06..07f1c628 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -379,6 +379,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 d417ca80..af8aeb48 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -608,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 @@ -633,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 ' @@ -644,17 +644,17 @@ 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)          try: -            instance = ModelClass.objects.create(**validated_attrs) +            instance = ModelClass.objects.create(**validated_data)          except TypeError as exc:              msg = (                  'Got a `TypeError` when calling `%s.objects.create()`. ' @@ -679,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 ' @@ -690,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/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: diff --git a/tests/test_viewsets.py b/tests/test_viewsets.py new file mode 100644 index 00000000..4d18a955 --- /dev/null +++ b/tests/test_viewsets.py @@ -0,0 +1,35 @@ +from django.test import TestCase +from rest_framework import status +from rest_framework.response import Response +from rest_framework.test import APIRequestFactory +from rest_framework.viewsets import GenericViewSet + + +factory = APIRequestFactory() + + +class BasicViewSet(GenericViewSet): +    def list(self, request, *args, **kwargs): +        return Response({'ACTION': 'LIST'}) + + +class InitializeViewSetsTestCase(TestCase): +    def test_initialize_view_set_with_actions(self): +        request = factory.get('/', '', content_type='application/json') +        my_view = BasicViewSet.as_view(actions={ +            'get': 'list', +        }) + +        response = my_view(request) +        self.assertEqual(response.status_code, status.HTTP_200_OK) +        self.assertEqual(response.data, {'ACTION': 'LIST'}) + +    def test_initialize_view_set_with_empty_actions(self): +        try: +            BasicViewSet.as_view() +        except TypeError as e: +            self.assertEqual(str(e), "The `actions` argument must be provided " +                                     "when calling `.as_view()` on a ViewSet. " +                                     "For example `.as_view({'get': 'list'})`") +        else: +            self.fail("actions must not be empty.") | 
