Найти тему
Computer Pro

Руководство по представлениям API в Django REST Framework. Часть 1 APIView

Оглавление

В этом руководстве дается всесторонний обзор представлений API DRF. Оно разделено на три части. Первая часть посвящена классу APIView.

Просто картинка с южного берега Белого моря. Фото автора
Просто картинка с южного берега Белого моря. Фото автора

В этом руководстве дается всесторонний обзор представлений API DRF. Оно разделено на три части:

  • В первой части рассматриваются основы представлений API, что они собой представляют, их назначение и как их писать.
  • Во второй части объясняются GenericAPIView и другие классы, предоставляемые DRF для работы с моделями баз данных и упрощения вашей жизни в целом.
  • В третьей части описывается обратное проектирование того, что происходит внутри представления API во время запроса пользователя. Знание этого пригодится при создании более сложных решений с привязкой к проекту (все мы рано или поздно сталкиваемся с ними).

Что такое APIView в DRF?

Представления API, пожалуй, являются наиболее важным элементом Django REST Framework. Они отвечают за большую часть логики обработки запросов, хотя и делегируют большую часть работы другим компонентам.

Проще говоря, представления API обрабатывают входящие запросы пользователей, генерируют соответствующий ответ и обеспечивают выполнение необходимых проверок и противовесов на этом пути. К ним относятся:

  • Аутентификация и авторизация пользователя
  • Проверка и применение регуляторов API
  • Сериализация и десериализация данных
  • Извлечение данных из базы данных и сохранение в ней
  • Повышение уровня проверки и другие условные ошибки

Представления API являются выдающимся примером хорошего дизайна ООП (объектно-ориентированного программирования). Они скрывают большую часть логики обработки, но оставляют вам несколько свойств, позволяющих легко настроить их поведение желаемым образом.

Чаще всего вы будете настраивать поведение своих представлений API с помощью settings.py файла. Параметры, которые вы там определяете, будут применены ко всем из них.

Однако вам необходимо создать логику, зависящую от запроса, для каждого представления API в отдельности. В конце концов, каждое из них предназначено для выполнения определенной цели. Это делается путем объявления таких методов, как get() и post(), которые часто называют обработчиками.

Как использовать представления API?

Давайте рассмотрим несколько примеров кода, демонстрирующих представления API в действии.

Предварительные условия и допущения

Чтобы эта статья была краткой и актуальной, я собираюсь сделать несколько предположений:

  • У вас есть базовые знания о Django framework
  • В вашей системе установлен Python 3.6+
  • Установлены pip install django, djangorestframework, django-filter, drf-yasg
  • Вы создали пустой проект (название, как душе угодно), с приложением, скажем, myapp. В myapp, создан файл urls.py который прописан в корневом urls.py:
    path('myapp/', include('myapp.urls'))
установление зависимостей
установление зависимостей

Пример обработчика запроса GET

Давайте рассмотрим этот простой пример представления API, который обрабатывает входящий запрос GET и возвращает случайное число от 1 до 10:

-3

Далее нам нужно зарегистрировать наше представление в urls.py файле:

-4

Если все правильно сделано то по адресу типа http://127.0.0.1:8000/myapp/random-number/ должна появиться страница:

если обновлять страницу то число будет меняться
если обновлять страницу то число будет меняться

Тоже самое можно выполнить и в консоли, запуская команду:

Так же число меняется...
Так же число меняется...

Пример обработчика запроса POST

Подобным образом напишем обработчик POST запросов. Который так же будет принимать два числа и генерировать случайное число от min до max.

-7
Появилась форма для отправки POST запроса, попробуем отправить запрос в котором словарь с ключами min и max, со значениями 10 и 20
Появилась форма для отправки POST запроса, попробуем отправить запрос в котором словарь с ключами min и max, со значениями 10 и 20
-9

Ну вот, всё работает, такой же запрос можно сделать и из командной строки:

только тут уже приходится экранировать кавычки обратным слэшем \
только тут уже приходится экранировать кавычки обратным слэшем \

Прием параметров из URL адреса

Параметры min и max можно передать из через URL, которая будет выглядеть подобным образом:

http://127.0.0.1:8000/myapp/random-number/min_num/int/max_num/int

Для этого слегка исправим функцию get в файле views.py и конечную точку в файле urls.py (приложения myapp):

-11
-12

В браузере у меня это дело выглядело так:

-13

Добавление политик к представлениям API

Представления API позволяют легко применять так называемые политики или настраивать их поведение. Это может быть метод аутентификации пользователя, модель пользовательских разрешений, анализаторы запросов, регуляторы API, средства визуализации ответов и т.д.

Обычно вы указываете их внутри settings.py. Но в некоторых случаях вы можете захотеть, чтобы конечная точка вела себя по-другому. Например, конечная точка входа пользователя не требует аутентификации, в то время как остальная часть API требует.

Политики имеют более высокий приоритет над директивами, представленными в settings.py. Они добавляются с помощью специальных свойств класса, показанных ниже.

-14

Можно оставить пустые квадратные скобки [ ] в качестве значения любого из этих свойств, чтобы не применять политику, но для полей parser_classes и renderer_classes этого делать не рекомендуется.

Что же лучше? Представления на основе классов или функций?

Представления API Rest Framework могут быть созданы как на основе классов, так и функций. Для простых эндпойнтов чаще используются функции, ибо это проще.

Для преобразовании функции в API-представление используется специальный декоратор: @api_view

-15
-16

Довольно изящно, не правда ли? Но не слишком увлекайтесь – магия, стоящая за этим, довольно проста.

Под капотом декоратор генерирует анонимный экземпляр APIView класса. Затем он устанавливает нашу функцию в качестве его обработчика по умолчанию. Таким образом, представления на основе функций - это не более чем ярлык для представления на основе классов.

ЗЫ. Это не работает, ибо получается ошибка:

-17

Это лечится добавлением в декоратор списка разрешенных методов:

в данной функции можно было указать один лишь метод GET, POST привел лишь для примера того что это список...
в данной функции можно было указать один лишь метод GET, POST привел лишь для примера того что это список...
Ну вот теперь всё работает, но если я уберу из декоратора метод POST, то форма ниже - исчезнет...
Ну вот теперь всё работает, но если я уберу из декоратора метод POST, то форма ниже - исчезнет...

ПРИМЕЧАНИЕ: Чтобы быть более точным, вызывается класс, созданный @api_view декоратором WrappedAPIView. Это особый подклассAPIView, но функционально они почти одинаковы.

Если вы хотите, чтобы представление на основе функций принимало параметры URL-пути, здесь применим тот же метод. Функции необходимо принять требуемые параметры, и они должны были бы быть указаны в URL-пути конечной точки.

Обработка POST-запросов

По умолчанию, декоратор @api_view будет предполагать, что наше представление должно принимать только запросы GET. Все остальные запросы будут возвращать ошибку 405. Но можно обойти это и посылать запросы POST:

POST запрос можно послать либо из браузера, либо из командной строки на URL http://127.0.0.1:8000/myapp/random-number/
POST запрос можно послать либо из браузера, либо из командной строки на URL http://127.0.0.1:8000/myapp/random-number/
-21
-22

Для использования в простых эндпойнтах, представления на основе функций подойдут как нельзя лучше. В сложных случаях - предпочтительны представления на основе классов.

Применение политик API

Настроить представления на основе функций можно с помощью дополнительных декораторов, с соответствующими именами, как показано ниже:

Само собой это только примерные варианты декораторов, после каждой точки ([authentication.*])могут быть еще много вариантов
Само собой это только примерные варианты декораторов, после каждой точки ([authentication.*])могут быть еще много вариантов

Список может быть пустым в качестве параметра, чтобы не иметь классов политики @authentication_classes([ ])

Когда использовать класс APIView?

Важно понимать, что класс APIView это класс "низкого уровня". Это первый уровень надстройки, которую Django REST Framework создает поверх стандартного View класса Django.

Таким образом, APIView класс определяет базовую логику для построения конечных точек API, но у него нет никакой логики, связанной с работой с моделями баз данных.

Для работы с моделями баз данных DRF предоставляет подкласс APIView called GenericAPIView, а также несколько других подклассов. Вот тут все становится по-настоящему интересным! Вторая часть этого повествования, которая будет опубликована в ближайшее время, будет посвящена этой теме.

Но когда имеет смысл использовать APIView класс? Как правило, когда конечная точка вашего API не выполняет операции CRUD (создание, чтение, обновление, удаление) над моделями баз данных. Вот несколько примеров, где это может быть применимо:

  • Конечные точки входа, выхода из системы, восстановления пароля
  • Панели мониторинга
  • Для обслуживания статических файлов и изображений
  • Конечные точки, генерирующие отчеты или статистику
  • При агрегировании данных из внешних ресурсов (например, через сторонние API)

Заключение

Структура классов представлений в Django REST Framework иерархическая. В первой части этого руководства мы рассмотрели первый и самый фундаментальный класс – APIView.

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

Мы также затронули представления на основе функций, которые являются удобным способом создания представлений на основе классов с меньшим количеством строк кода (при правильном использовании).

В следующей части этого руководства будут рассмотрены GenericAPIView и другие подклассы APIView, используемые для работы с моделями баз данных.