django-rest_framework - Request and response

Keywords: JSON Python REST Django

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.

Posted by NFD on Sun, 14 Jun 2020 01:32:55 -0700