Requests and responses
Request object
The REST framework introduces a Request object, which extends the ordinary HttpRequest and provides more flexible and clear parsing. The core function of the Request object is request.data Property, which corresponds to the request.POST Similar, but more useful for using web APIs.
request.POST # Only handles form data. Only works for 'POST' method. request.data # Handles arbitrary data. Works for 'POST', 'PUT' and 'PATCH' methods.
Response object
request Response(data) #Renders to content type as requested by the client
Status code
It's not easy to read HTTP status codes in view, and it's easy to notice whether the error codes are incorrect. The REST framework provides a clearer identifier for each status code, such as HTTP_400_BAD_REQUEST in the status module, it's best to always use them instead of using numeric identifiers.
Packaging API view
The REST framework provides two decorators for writing API views
1. The @ api_view decoration and work based on function view
2. The APIView is based on class view
These decorators provide some functionality to ensure that instances are received in the Request and added to the Response object. Decorator behavior, such as 405 Method Not Allowed returning a Response when appropriate, and handling any exceptions that occur when ParseError access is made with malformed input request.data
Change Views
Edit snippets/views.py
from rest_framework import status from rest_framework.response import Response from rest_framework.decorators import api_view from .models import Snippet from .serializers import SnippetSerializer @api_view(['GET','POST']) def snippet_list(request): if request.method=='GET' snippets=Snippet.objects.all() serilizer=SnippetSerializer(snippets,many=True) return Response(serilizer.data) elif request.method=="POST": serlizer=SnippetSerializer(data=request.data) if serlizer.is_valid(): serlizer.save() return Response(serlizer.data,status=status.HTTP_201_CREATED) return Response(serlizer.error,status=status.HTTP_400_BAD_REQUEST)
Our instance view is a more concise improvement of the previous one, and now the code feels very similar to when we use the Form API. We also use named status codes, which make the meaning of the response more obvious.
This is views.py A view of a single snippet in a module.
@api_view(['GET','PUT','DELETE']) def snippet_detail(request,pk) try: snippet=Snippet.objects.get(pk=pk) except Snippet.DoesNotExist: return Resopse(status=status.HTTP_404_NOT_FOUND if request.method=='GET': serializer=SnippetSerializer(snippet) return Response(serializer.data) elif request.method=='PUT': serializer=SnippetSerializer(snippet,data=request.data) if serializer.is_valid(): serializer.save() return=Response(serializer.data) return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST) elif request.method=='DELETE': snippet.delete() return Response(status=status.HTTP_204_NO_CONTENT)
It's not much different from the regular Django view.
Note that we no longer explicitly bind our request or response to the specified content type, request.data You can pass in json requests, but you can also process other formats. Similarly, we return response types with data, but allow the REST framework to present the response as the correct content type for us.
Add an optional format suffix to our web address
To take advantage of the fact that our response is no longer hardwired to a single content type, add support for format suffixes to API endpoints. Using format suffixes can provide us with URLs that explicitly refer to a given format, which means that our API will be able to handle http://example.com/api/items/4.json URLs like that.
First, add the format keyword parameter to the two attempts, as follows
def snippet_list(request,format=None)
def snippet_detail(request,pk,format=None)
Now snippet/urls.py Need to update, format_suffix_patterns append a group
from django.urls import path from rest_framework.urlpatterns import format_suffix_patterns from snippets import views urlpatterns=[ path('snippets/',views.snippet_list), path('snippets/<int:pk>',views.snippet_detail), ] urlpatterns=format_suffix_patterns(urlpatterns)
We don't have to add these extra url patterns, but it provides a simple and clean way to refer to specific formats.
You can test the API.
python manage.py runserver
Browser open http://127.0.0.1:8000/snippets/
HTTP 200 OK Allow: GET, OPTIONS, POST Content-Type: application/json Vary: Accept [ { "id": 1, "title": "", "code": "foo = \"bar\"\n", "linenos": false, "language": "python", "style": "friendly" }, { "id": 2, "title": "", "code": "print(\"hello, world\")\n", "linenos": false, "language": "python", "style": "friendly" }, { "id": 3, "title": "", "code": "print(\"hello, world\")", "linenos": false, "language": "python", "style": "friendly" } ]
Visit http://127.0.0.1:8000/snippets/1/
GET /snippets/1/ HTTP 200 OK Allow: GET, OPTIONS, POST, PUT Content-Type: application/json Vary: Accept { "id": 1, "title": "", "code": "foo = \"bar\"\n", "linenos": false, "language": "python", "style": "friendly" }
The response format returned can be controlled by the Accept header
http://127.0.0.1:8000/snippets/ Accept:application/json # Request JSON http://127.0.0.1:8000/snippets/ Accept:text/html # Request HTML
Or by adding a format suffix:
http://127.0.0.1:8000/snippets.json # JSON suffix http://127.0.0.1:8000/snippets.api # Browsable API suffix
You can also control the content type to control the format of the sent request. Next, use the http module to send the request.
# POST using form data http --form POST http://127.0.0.1:8000/snippets/ code="print(123)" { "id": 3, "title": "", "code": "print(123)", "linenos": false, "language": "python", "style": "friendly" } # POST using JSON http --json POST http://127.0.0.1:8000/snippets/ code="print(456)" { "id": 4, "title": "", "code": "print(456)", "linenos": false, "language": "python", "style": "friendly" }
If you add the http switch to -- debug, you can see the request type.