aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/index.md2
-rw-r--r--docs/tutorial/1-serialization.md24
-rw-r--r--docs/tutorial/quickstart.md3
-rw-r--r--rest_framework/renderers.py4
-rw-r--r--rest_framework/serializers.py28
-rw-r--r--rest_framework/viewsets.py6
-rw-r--r--tests/test_viewsets.py35
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.")