Strip trailing spaces in tutorial

This commit is contained in:
sshquack 2014-08-15 20:45:28 -06:00
parent 14867705e9
commit 867e441ec0
6 changed files with 49 additions and 49 deletions

View File

@ -81,8 +81,8 @@ For the purposes of this tutorial we're going to start by creating a simple `Sni
LEXERS = [item for item in get_all_lexers() if item[1]] LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS]) LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles()) STYLE_CHOICES = sorted((item, item) for item in get_all_styles())
class Snippet(models.Model): class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='') title = models.CharField(max_length=100, blank=True, default='')
@ -94,7 +94,7 @@ For the purposes of this tutorial we're going to start by creating a simple `Sni
style = models.CharField(choices=STYLE_CHOICES, style = models.CharField(choices=STYLE_CHOICES,
default='friendly', default='friendly',
max_length=100) max_length=100)
class Meta: class Meta:
ordering = ('created',) ordering = ('created',)
@ -122,12 +122,12 @@ The first thing we need to get started on our Web API is to provide a way of ser
default='python') default='python')
style = serializers.ChoiceField(choices=STYLE_CHOICES, style = serializers.ChoiceField(choices=STYLE_CHOICES,
default='friendly') default='friendly')
def restore_object(self, attrs, instance=None): def restore_object(self, attrs, instance=None):
""" """
Create or update a new snippet instance, given a dictionary Create or update a new snippet instance, given a dictionary
of deserialized field values. of deserialized field values.
Note that if we don't define this method, then deserializing Note that if we don't define this method, then deserializing
data will simply return a dictionary of items. data will simply return a dictionary of items.
""" """
@ -180,7 +180,7 @@ At this point we've translated the model instance into Python native datatypes.
content content
# '{"pk": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}' # '{"pk": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'
Deserialization is similar. First we parse a stream into Python native datatypes... Deserialization is similar. First we parse a stream into Python native datatypes...
# This import will use either `StringIO.StringIO` or `io.BytesIO` # This import will use either `StringIO.StringIO` or `io.BytesIO`
# as appropriate, depending on if we're running Python 2 or Python 3. # as appropriate, depending on if we're running Python 2 or Python 3.
@ -196,7 +196,7 @@ Deserialization is similar. First we parse a stream into Python native datatype
# True # True
serializer.object serializer.object
# <Snippet: Snippet object> # <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. 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.
We can also serialize querysets instead of model instances. To do so we simply add a `many=True` flag to the serializer arguments. We can also serialize querysets instead of model instances. To do so we simply add a `many=True` flag to the serializer arguments.
@ -264,7 +264,7 @@ The root of our API is going to be a view that supports listing all the existing
return JSONResponse(serializer.data, status=201) return JSONResponse(serializer.data, status=201)
return JSONResponse(serializer.errors, status=400) return JSONResponse(serializer.errors, status=400)
Note that because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as `csrf_exempt`. This isn't something that you'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now. Note that because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as `csrf_exempt`. This isn't something that you'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now.
We'll also need a view which corresponds to an individual snippet, and can be used to retrieve, update or delete the snippet. We'll also need a view which corresponds to an individual snippet, and can be used to retrieve, update or delete the snippet.
@ -277,11 +277,11 @@ We'll also need a view which corresponds to an individual snippet, and can be us
snippet = Snippet.objects.get(pk=pk) snippet = Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist: except Snippet.DoesNotExist:
return HttpResponse(status=404) return HttpResponse(status=404)
if request.method == 'GET': if request.method == 'GET':
serializer = SnippetSerializer(snippet) serializer = SnippetSerializer(snippet)
return JSONResponse(serializer.data) return JSONResponse(serializer.data)
elif request.method == 'PUT': elif request.method == 'PUT':
data = JSONParser().parse(request) data = JSONParser().parse(request)
serializer = SnippetSerializer(snippet, data=data) serializer = SnippetSerializer(snippet, data=data)

View File

@ -33,7 +33,7 @@ The wrappers also provide behaviour such as returning `405 Method Not Allowed` r
## Pulling it all together ## Pulling it all together
Okay, let's go ahead and start using these new components to write a few views. Okay, let's go ahead and start using these new components to write a few views.
We don't need our `JSONResponse` class in `views.py` anymore, so go ahead and delete that. Once that's done we can start refactoring our views slightly. We don't need our `JSONResponse` class in `views.py` anymore, so go ahead and delete that. Once that's done we can start refactoring our views slightly.
@ -69,7 +69,7 @@ Here is the view for an individual snippet, in the `views.py` module.
def snippet_detail(request, pk): def snippet_detail(request, pk):
""" """
Retrieve, update or delete a snippet instance. Retrieve, update or delete a snippet instance.
""" """
try: try:
snippet = Snippet.objects.get(pk=pk) snippet = Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist: except Snippet.DoesNotExist:
@ -115,7 +115,7 @@ Now update the `urls.py` file slightly, to append a set of `format_suffix_patter
url(r'^snippets/$', 'snippet_list'), url(r'^snippets/$', 'snippet_list'),
url(r'^snippets/(?P<pk>[0-9]+)$', 'snippet_detail'), url(r'^snippets/(?P<pk>[0-9]+)$', 'snippet_detail'),
) )
urlpatterns = format_suffix_patterns(urlpatterns) urlpatterns = format_suffix_patterns(urlpatterns)
We don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of referring to a specific format. We don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of referring to a specific format.
@ -146,7 +146,7 @@ Similarly, we can control the format of the request that we send, using the `Con
curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123" curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123"
{"id": 3, "title": "", "code": "print 123", "linenos": false, "language": "python", "style": "friendly"} {"id": 3, "title": "", "code": "print 123", "linenos": false, "language": "python", "style": "friendly"}
# POST using JSON # POST using JSON
curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Content-Type: application/json" curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Content-Type: application/json"

View File

@ -30,7 +30,7 @@ We'll start by rewriting the root view as a class based view. All this involves
return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
So far, so good. It looks pretty similar to the previous case, but we've got better separation between the different HTTP methods. We'll also need to update the instance view in `views.py`. So far, so good. It looks pretty similar to the previous case, but we've got better separation between the different HTTP methods. We'll also need to update the instance view in `views.py`.
class SnippetDetail(APIView): class SnippetDetail(APIView):
""" """
@ -72,7 +72,7 @@ We'll also need to refactor our `urls.py` slightly now we're using class based v
url(r'^snippets/$', views.SnippetList.as_view()), url(r'^snippets/$', views.SnippetList.as_view()),
url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()), url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
) )
urlpatterns = format_suffix_patterns(urlpatterns) urlpatterns = format_suffix_patterns(urlpatterns)
Okay, we're done. If you run the development server everything should be working just as before. Okay, we're done. If you run the development server everything should be working just as before.

View File

@ -73,12 +73,12 @@ We'll also add a couple of views to `views.py`. We'd like to just use read-only
class UserList(generics.ListAPIView): class UserList(generics.ListAPIView):
queryset = User.objects.all() queryset = User.objects.all()
serializer_class = UserSerializer serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView): class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all() queryset = User.objects.all()
serializer_class = UserSerializer serializer_class = UserSerializer
Make sure to also import the `UserSerializer` class Make sure to also import the `UserSerializer` class
from snippets.serializers import UserSerializer from snippets.serializers import UserSerializer
@ -157,8 +157,8 @@ To do that we're going to need to create a custom permission.
In the snippets app, create a new file, `permissions.py` In the snippets app, create a new file, `permissions.py`
from rest_framework import permissions from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission): class IsOwnerOrReadOnly(permissions.BasePermission):
""" """
Custom permission to only allow owners of an object to edit it. Custom permission to only allow owners of an object to edit it.
@ -201,7 +201,7 @@ If we try to create a snippet without authenticating, we'll get an error:
We can make a successful request by including the username and password of one of the users we created earlier. We can make a successful request by including the username and password of one of the users we created earlier.
curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 789" -u tom:password curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 789" -u tom:password
{"id": 5, "owner": "tom", "title": "foo", "code": "print 789", "linenos": false, "language": "python", "style": "friendly"} {"id": 5, "owner": "tom", "title": "foo", "code": "print 789", "linenos": false, "language": "python", "style": "friendly"}
## Summary ## Summary

View File

@ -1,6 +1,6 @@
# Tutorial 5: Relationships & Hyperlinked APIs # Tutorial 5: Relationships & Hyperlinked APIs
At the moment relationships within our API are represented by using primary keys. In this part of the tutorial we'll improve the cohesion and discoverability of our API, by instead using hyperlinking for relationships. At the moment relationships within our API are represented by using primary keys. In this part of the tutorial we'll improve the cohesion and discoverability of our API, by instead using hyperlinking for relationships.
## Creating an endpoint for the root of our API ## Creating an endpoint for the root of our API
@ -37,7 +37,7 @@ Instead of using a concrete generic view, we'll use the base class for represent
class SnippetHighlight(generics.GenericAPIView): class SnippetHighlight(generics.GenericAPIView):
queryset = Snippet.objects.all() queryset = Snippet.objects.all()
renderer_classes = (renderers.StaticHTMLRenderer,) renderer_classes = (renderers.StaticHTMLRenderer,)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
snippet = self.get_object() snippet = self.get_object()
return Response(snippet.highlighted) return Response(snippet.highlighted)
@ -78,16 +78,16 @@ We can easily re-write our existing serializers to use hyperlinking. In your `sn
class SnippetSerializer(serializers.HyperlinkedModelSerializer): class SnippetSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.Field(source='owner.username') owner = serializers.Field(source='owner.username')
highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html') highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')
class Meta: class Meta:
model = Snippet model = Snippet
fields = ('url', 'highlight', 'owner', fields = ('url', 'highlight', 'owner',
'title', 'code', 'linenos', 'language', 'style') 'title', 'code', 'linenos', 'language', 'style')
class UserSerializer(serializers.HyperlinkedModelSerializer): class UserSerializer(serializers.HyperlinkedModelSerializer):
snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail') snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail')
class Meta: class Meta:
model = User model = User
fields = ('url', 'username', 'snippets') fields = ('url', 'username', 'snippets')
@ -126,9 +126,9 @@ After adding all those names into our URLconf, our final `snippets/urls.py` file
views.UserDetail.as_view(), views.UserDetail.as_view(),
name='user-detail') name='user-detail')
)) ))
# Login and logout views for the browsable API # Login and logout views for the browsable API
urlpatterns += patterns('', urlpatterns += patterns('',
url(r'^api-auth/', include('rest_framework.urls', url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')), namespace='rest_framework')),
) )

View File

@ -46,14 +46,14 @@ First up we're going to define some serializers in `quickstart/serializers.py` t
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User, Group
from rest_framework import serializers from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer): class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta: class Meta:
model = User model = User
fields = ('url', 'username', 'email', 'groups') fields = ('url', 'username', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer): class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta: class Meta:
model = Group model = Group
@ -68,16 +68,16 @@ Right, we'd better write some views then. Open `quickstart/views.py` and get ty
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User, Group
from rest_framework import viewsets from rest_framework import viewsets
from quickstart.serializers import UserSerializer, GroupSerializer from quickstart.serializers import UserSerializer, GroupSerializer
class UserViewSet(viewsets.ModelViewSet): class UserViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows users to be viewed or edited. API endpoint that allows users to be viewed or edited.
""" """
queryset = User.objects.all() queryset = User.objects.all()
serializer_class = UserSerializer serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet): class GroupViewSet(viewsets.ModelViewSet):
""" """
API endpoint that allows groups to be viewed or edited. API endpoint that allows groups to be viewed or edited.
@ -144,22 +144,22 @@ We're now ready to test the API we've built. Let's fire up the server from the
We can now access our API, both from the command-line, using tools like `curl`... We can now access our API, both from the command-line, using tools like `curl`...
bash: curl -H 'Accept: application/json; indent=4' -u admin:password http://127.0.0.1:8000/users/ bash: curl -H 'Accept: application/json; indent=4' -u admin:password http://127.0.0.1:8000/users/
{ {
"count": 2, "count": 2,
"next": null, "next": null,
"previous": null, "previous": null,
"results": [ "results": [
{ {
"email": "admin@example.com", "email": "admin@example.com",
"groups": [], "groups": [],
"url": "http://127.0.0.1:8000/users/1/", "url": "http://127.0.0.1:8000/users/1/",
"username": "admin" "username": "admin"
}, },
{ {
"email": "tom@example.com", "email": "tom@example.com",
"groups": [ ], "groups": [ ],
"url": "http://127.0.0.1:8000/users/2/", "url": "http://127.0.0.1:8000/users/2/",
"username": "tom" "username": "tom"
} }
] ]