diff options
| -rw-r--r-- | docs/api-guide/serializers.md | 8 | ||||
| -rw-r--r-- | docs/tutorial/1-serialization.md | 26 | ||||
| -rw-r--r-- | docs/tutorial/quickstart.md | 3 | ||||
| -rw-r--r-- | rest_framework/renderers.py | 5 | ||||
| -rw-r--r-- | tests/test_renderers.py | 9 | 
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):      """ | 
