Spec-Zone.ru › Django REST Framework

Урок 2: Запросы и ответы

Начиная с этого момента мы переходим к изучению основ REST-фреймворка. Давайте представим несколько основных строительных блоков.

Объекты запроса

REST фреймворк предоставляет объект Request, который расширяет обычный HttpRequest, и обеспечивает более гибкий синтаксический анализ запроса. Основной функциональностью объекта Request является атрибут request.data, который похож на request.POST, но более удобен для работы с веб-API.

request.POST  # Only handles form data.  Only works for 'POST' method.
request.data  # Handles arbitrary data.  Works for 'POST', 'PUT' and 'PATCH' methods.

Объекты ответа

REST фреймворк также предоставляет объект Response, который является типом TemplateResponse, принимающим неотформатированный контент и использующим переговорный протокол контента для определения правильного типа контента, который нужно вернуть клиенту.

return Response(data)  # Renders to content type as requested by the client.

Коды состояния

Использование числовых кодов состояния HTTP в ваших представлениях не всегда обеспечивает чтение, и легко упустить из виду, если вы ошиблись с кодом ошибки. REST фреймворк предоставляет более явные идентификаторы для каждого кода состояния, такие как HTTP_400_BAD_REQUEST в модуле status. Рекомендуется использовать их вместо числовых идентификаторов.

Оборачивание представлений API

REST фреймворк предоставляет два обёртки, которые вы можете использовать для написания представлений API.

  1. Декоратор @api_view для работы с представлениями на основе функций.
  2. Класс APIView для работы с представлениями на основе классов.

Эти обёртки предоставляют несколько функций, такие как гарантирование того, что вы получаете экземпляры Request в своём представлении, и добавление контекста к объектам Response для выполнения переговорного протокола контента.

Обёртки также обеспечивают поведение, такое как возвращение ответов 405 Method Not Allowed при необходимости и обработку любых исключений ParseError , возникающих при доступе к request.data с неверным вводом.

Объединение всего

Хорошо, давайте начнём использовать эти новые компоненты, чтобы немного переработать наши представления.

from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer


@api_view(['GET', 'POST'])
def snippet_list(request):
    """
    List all code snippets, or create a new snippet.
    """
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Наше представление экземпляра улучшено по сравнению с предыдущим примером. Оно немного более лаконично, и код теперь очень похож на работу с API форм. Мы также используем именованные коды состояния, что делает значения ответа более очевидными.

Вот представление для отдельного фрагмента в модуле views.py.

@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a code snippet.
    """
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return Response(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)

Всё это должно быть очень знакомо - это не сильно отличается от работы с обычными представлениями Django.

Обратите внимание, что мы больше не явно связываем наши запросы или ответы с конкретным типом контента. request.data может обрабатывать входящие json запросы, но также может обрабатывать и другие форматы. Аналогично, мы возвращаем объекты ответа с данными, но позволяем REST фреймворку отобразить ответ в правильный тип контента для нас.

Добавление необязательных суффиксов формата к нашим URL

Чтобы воспользоваться тем, что наши ответы больше не привязаны к одному типу контента, добавим поддержку суффиксов форматов к нашим конечным точкам API. Использование суффиксов форматов даёт нам URL, которые явно ссылаются на определённый формат, и означает, что наш API сможет обрабатывать URL, такие как http://example.com/api/items/4.json.

Начните с добавления ключевого аргумента format в оба представления, как показано ниже.

def snippet_list(request, format=None):

и

def snippet_detail(request, pk, format=None):

Теперь немного измените файл snippets/urls.py, чтобы добавить набор format_suffix_patterns в дополнение к существующим URL.

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)

Мы необязательно должны добавить эти дополнительные шаблоны URL, но это даёт нам простой и чистый способ ссылки на конкретный формат.

Как это выглядит?

Протестируйте API из командной строки, как мы делали в части 1 руководства. Всё работает примерно так же, хотя у нас есть более удобная обработка ошибок, если мы отправим неверные запросы.

Как и прежде, мы можем получить список всех фрагментов.

http http://127.0.0.1:8000/snippets/

HTTP/1.1 200 OK
...
[
  {
    "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"
  }
]

Мы можем управлять форматом ответа, который получаем, либо с помощью заголовка Accept:

http http://127.0.0.1:8000/snippets/ Accept:application/json  # Request JSON
http http://127.0.0.1:8000/snippets/ Accept:text/html         # Request HTML

Или добавив суффикс формата:

http http://127.0.0.1:8000/snippets.json  # JSON suffix
http http://127.0.0.1:8000/snippets.api   # Browsable API suffix

Аналогично, мы можем управлять форматом запроса, который отправляем, с помощью заголовка Content-Type.

# 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"
}

Если вы добавите переключатель --debug к запросам http выше, вы сможете увидеть тип запроса в заголовках запроса.

Теперь откройте API в веб-браузере, перейдя по адресу http://127.0.0.1:8000/snippets/.

Возможность просмотра

Поскольку API выбирает тип контента ответа на основе запроса клиента, по умолчанию он будет возвращать HTML-версию ресурса, когда этот ресурс запрашивается веб-браузером. Это позволяет API возвращать полностью просматриваемое в веб-браузере представление HTML.

Возможность просмотра API — это очень удобная функция, которая значительно упрощает разработку и использование вашего API. Она также значительно снижает порог вхождения для других разработчиков, желающих исследовать и работать с вашим API.

Более подробную информацию о функции просматриваемого API и способах его настройки можно найти в разделе просматриваемого API.

Что дальше?

В части 3 руководства мы начнём использовать представления на основе классов и увидим, как обобщённые представления уменьшают объём необходимого кода.

Copyright © 2011–present Encode OSS Ltd.
Licensed under the BSD License.
https://www.django-rest-framework.org/tutorial/2-requests-and-responses/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API