mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 17:47:04 +03:00
Strip trailing spaces in tutorial
This commit is contained in:
parent
14867705e9
commit
867e441ec0
|
@ -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]]
|
||||
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
|
||||
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())
|
||||
|
||||
|
||||
|
||||
|
||||
class Snippet(models.Model):
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
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,
|
||||
default='friendly',
|
||||
max_length=100)
|
||||
|
||||
|
||||
class Meta:
|
||||
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')
|
||||
style = serializers.ChoiceField(choices=STYLE_CHOICES,
|
||||
default='friendly')
|
||||
|
||||
|
||||
def restore_object(self, attrs, instance=None):
|
||||
"""
|
||||
Create or update a new snippet instance, given a dictionary
|
||||
of deserialized field values.
|
||||
|
||||
|
||||
Note that if we don't define this method, then deserializing
|
||||
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
|
||||
# '{"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`
|
||||
# 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
|
||||
serializer.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.
|
||||
|
||||
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.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.
|
||||
|
||||
|
@ -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)
|
||||
except Snippet.DoesNotExist:
|
||||
return HttpResponse(status=404)
|
||||
|
||||
|
||||
if request.method == 'GET':
|
||||
serializer = SnippetSerializer(snippet)
|
||||
return JSONResponse(serializer.data)
|
||||
|
||||
|
||||
elif request.method == 'PUT':
|
||||
data = JSONParser().parse(request)
|
||||
serializer = SnippetSerializer(snippet, data=data)
|
||||
|
|
|
@ -33,7 +33,7 @@ The wrappers also provide behaviour such as returning `405 Method Not Allowed` r
|
|||
|
||||
## 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.
|
||||
|
||||
|
@ -69,7 +69,7 @@ Here is the view for an individual snippet, in the `views.py` module.
|
|||
def snippet_detail(request, pk):
|
||||
"""
|
||||
Retrieve, update or delete a snippet instance.
|
||||
"""
|
||||
"""
|
||||
try:
|
||||
snippet = Snippet.objects.get(pk=pk)
|
||||
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/(?P<pk>[0-9]+)$', 'snippet_detail'),
|
||||
)
|
||||
|
||||
|
||||
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.
|
||||
|
@ -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"
|
||||
|
||||
{"id": 3, "title": "", "code": "print 123", "linenos": false, "language": "python", "style": "friendly"}
|
||||
|
||||
|
||||
# POST using JSON
|
||||
curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Content-Type: application/json"
|
||||
|
||||
|
|
|
@ -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.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):
|
||||
"""
|
||||
|
@ -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/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
|
||||
)
|
||||
|
||||
|
||||
urlpatterns = format_suffix_patterns(urlpatterns)
|
||||
|
||||
Okay, we're done. If you run the development server everything should be working just as before.
|
||||
|
|
|
@ -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):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
|
||||
|
||||
|
||||
class UserDetail(generics.RetrieveAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
|
||||
Make sure to also import the `UserSerializer` class
|
||||
|
||||
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`
|
||||
|
||||
from rest_framework import permissions
|
||||
|
||||
|
||||
|
||||
|
||||
class IsOwnerOrReadOnly(permissions.BasePermission):
|
||||
"""
|
||||
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.
|
||||
|
||||
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"}
|
||||
|
||||
## Summary
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 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
|
||||
|
||||
|
@ -37,7 +37,7 @@ Instead of using a concrete generic view, we'll use the base class for represent
|
|||
class SnippetHighlight(generics.GenericAPIView):
|
||||
queryset = Snippet.objects.all()
|
||||
renderer_classes = (renderers.StaticHTMLRenderer,)
|
||||
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
snippet = self.get_object()
|
||||
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):
|
||||
owner = serializers.Field(source='owner.username')
|
||||
highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')
|
||||
|
||||
|
||||
class Meta:
|
||||
model = Snippet
|
||||
fields = ('url', 'highlight', 'owner',
|
||||
'title', 'code', 'linenos', 'language', 'style')
|
||||
|
||||
|
||||
|
||||
|
||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||
snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail')
|
||||
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
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(),
|
||||
name='user-detail')
|
||||
))
|
||||
|
||||
|
||||
# Login and logout views for the browsable API
|
||||
urlpatterns += patterns('',
|
||||
urlpatterns += patterns('',
|
||||
url(r'^api-auth/', include('rest_framework.urls',
|
||||
namespace='rest_framework')),
|
||||
)
|
||||
|
|
|
@ -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 rest_framework import serializers
|
||||
|
||||
|
||||
|
||||
|
||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('url', 'username', 'email', 'groups')
|
||||
|
||||
|
||||
|
||||
|
||||
class GroupSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
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 rest_framework import viewsets
|
||||
from quickstart.serializers import UserSerializer, GroupSerializer
|
||||
|
||||
|
||||
|
||||
|
||||
class UserViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows users to be viewed or edited.
|
||||
"""
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
|
||||
|
||||
|
||||
class GroupViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
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`...
|
||||
|
||||
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,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"count": 2,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"email": "admin@example.com",
|
||||
"groups": [],
|
||||
"url": "http://127.0.0.1:8000/users/1/",
|
||||
"email": "admin@example.com",
|
||||
"groups": [],
|
||||
"url": "http://127.0.0.1:8000/users/1/",
|
||||
"username": "admin"
|
||||
},
|
||||
},
|
||||
{
|
||||
"email": "tom@example.com",
|
||||
"groups": [ ],
|
||||
"url": "http://127.0.0.1:8000/users/2/",
|
||||
"email": "tom@example.com",
|
||||
"groups": [ ],
|
||||
"url": "http://127.0.0.1:8000/users/2/",
|
||||
"username": "tom"
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue
Block a user