aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/api-guide/serializers.md8
-rw-r--r--docs/tutorial/1-serialization.md26
-rw-r--r--docs/tutorial/quickstart.md3
-rw-r--r--rest_framework/renderers.py5
-rw-r--r--tests/test_renderers.py9
5 files changed, 29 insertions, 22 deletions
diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md
index 1779c863..ab44839f 100644
--- a/docs/api-guide/serializers.md
+++ b/docs/api-guide/serializers.md
@@ -326,9 +326,9 @@ Here's an example for an `update()` method on our previous `UserSerializer` clas
# would need to be handled.
profile = instance.profile
- user.username = validated_data.get('username', instance.username)
- user.email = validated_data.get('email', instance.email)
- user.save()
+ instance.username = validated_data.get('username', instance.username)
+ instance.email = validated_data.get('email', instance.email)
+ instance.save()
profile.is_premium_member = profile_data.get(
'is_premium_member',
@@ -340,7 +340,7 @@ Here's an example for an `update()` method on our previous `UserSerializer` clas
)
profile.save()
- return user
+ return instance
Because the behavior of nested creates and updates can be ambiguous, and may require complex dependancies between related models, REST framework 3 requires you to always write these methods explicitly. The default `ModelSerializer` `.create()` and `.update()` methods do not include support for writable nested representations.
diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md
index 52c75d2c..3621f01b 100644
--- a/docs/tutorial/1-serialization.md
+++ b/docs/tutorial/1-serialization.md
@@ -16,7 +16,6 @@ The tutorial is fairly in-depth, so you should probably get a cookie and a cup o
Before we do anything else we'll create a new virtual environment, using [virtualenv]. This will make sure our package configuration is kept nicely isolated from any other projects we're working on.
- :::bash
virtualenv env
source env/bin/activate
@@ -75,12 +74,8 @@ For the purposes of this tutorial we're going to start by creating a simple `Sni
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
- language = models.CharField(choices=LANGUAGE_CHOICES,
- default='python',
- max_length=100)
- style = models.CharField(choices=STYLE_CHOICES,
- default='friendly',
- max_length=100)
+ language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
+ style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
class Meta:
ordering = ('created',)
@@ -101,14 +96,11 @@ 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,
- max_length=100)
+ title = serializers.CharField(required=False, allow_blank=True, max_length=100)
code = serializers.CharField(style={'type': 'textarea'})
linenos = serializers.BooleanField(required=False)
- language = serializers.ChoiceField(choices=LANGUAGE_CHOICES,
- default='python')
- style = serializers.ChoiceField(choices=STYLE_CHOICES,
- default='friendly')
+ language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
+ style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')
def create(self, validated_data):
"""
@@ -181,7 +173,9 @@ Deserialization is similar. First we parse a stream into Python native datatype
serializer = SnippetSerializer(data=data)
serializer.is_valid()
# True
- serializer.object
+ serializer.validated_data
+ # OrderedDict([('title', ''), ('code', 'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
+ 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 +204,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 +295,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 46126d91..7c14ab8f 100644
--- a/rest_framework/renderers.py
+++ b/rest_framework/renderers.py
@@ -102,6 +102,11 @@ class JSONRenderer(BaseRenderer):
# and may (or may not) be unicode.
# On python 3.x json.dumps() returns unicode strings.
if isinstance(ret, six.text_type):
+ # We always fully escape \u2028 and \u2029 to ensure we output JSON
+ # that is a strict javascript subset. If bytes were returned
+ # by json.dumps() then we don't have these characters in any case.
+ # See: http://timelessrepo.com/json-isnt-a-javascript-subset
+ ret = ret.replace('\u2028', '\\u2028').replace('\u2029', '\\u2029')
return bytes(ret.encode('utf-8'))
return ret
diff --git a/tests/test_renderers.py b/tests/test_renderers.py
index 22eb5459..00a24fb1 100644
--- a/tests/test_renderers.py
+++ b/tests/test_renderers.py
@@ -386,6 +386,15 @@ class UnicodeJSONRendererTests(TestCase):
content = renderer.render(obj, 'application/json')
self.assertEqual(content, '{"countries":["United Kingdom","France","EspaƱa"]}'.encode('utf-8'))
+ def test_u2028_u2029(self):
+ # The \u2028 and \u2029 characters should be escaped,
+ # even when the non-escaping unicode representation is used.
+ # Regression test for #2169
+ obj = {'should_escape': '\u2028\u2029'}
+ renderer = JSONRenderer()
+ content = renderer.render(obj, 'application/json')
+ self.assertEqual(content, '{"should_escape":"\\u2028\\u2029"}'.encode('utf-8'))
+
class AsciiJSONRendererTests(TestCase):
"""