Запросы Django rest framework

Обновлено: 21.11.2024

Среда REST включает несколько вспомогательных классов, которые расширяют существующую среду тестирования Django и улучшают поддержку выполнения запросов API.

Создание тестовых запросов

Класс APIRequestFactory поддерживает API, почти идентичный стандартному классу RequestFactory Django. Это означает, что доступны стандартные методы .get(), .post(), .put(), .patch(), .delete(), .head() и .options().

Использование аргумента формата

Методы создания тела запроса, такие как post , put и patch , включают аргумент формата, что упрощает создание запросов с использованием типа контента, отличного от данных составной формы. Например:

По умолчанию доступны форматы «multipart» и «json». Для совместимости с существующим RequestFactory Django формат по умолчанию — «multipart».

Для поддержки более широкого набора форматов запросов или изменения формата по умолчанию см. раздел конфигурации.

Явное кодирование тела запроса

Если вам нужно явно закодировать тело запроса, вы можете сделать это, установив флаг content_type. Например:

PUT и PATCH с данными формы

Стоит отметить одно различие между RequestFactory Django и APIRequestFactory REST framework, которое состоит в том, что данные составной формы будут закодированы для методов, отличных от .post() .

Например, с помощью APIRequestFactory вы можете сделать запрос PUT формы следующим образом:

Используя RequestFactory Django, вам нужно будет явно кодировать данные самостоятельно:

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

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

Чтобы принудительно аутентифицировать запрос, используйте метод force_authenticate().

Сигнатура метода — force_authenticate(request, user=None, token=None) . При совершении вызова могут быть установлены один или оба из пользователя и токена.

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

Принудительная проверка CSRF

По умолчанию запросы, созданные с помощью APIRequestFactory, не будут подвергаться проверке CSRF при передаче в представление платформы REST. Если вам нужно явным образом включить проверку CSRF, вы можете сделать это, установив флаг force_csrf_checks при создании экземпляра фабрики.

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

Отправка запросов

Класс APIClient поддерживает тот же интерфейс запросов, что и стандартный класс Client Django. Это означает, что доступны стандартные методы .get(), .post(), .put(), .patch(), .delete(), .head() и .options(). Например:

Для поддержки более широкого набора форматов запросов или изменения формата по умолчанию см. раздел конфигурации.

Аутентификация

.login(**kwargs)

Метод входа работает точно так же, как и в обычном классе Client Django. Это позволяет вам аутентифицировать запросы для любых представлений, которые включают SessionAuthentication .

Чтобы выйти из системы, вызовите метод logout как обычно.

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

.credentials(**kwargs)

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

Обратите внимание, что повторный вызов учетных данных перезаписывает все существующие учетные данные. Вы можете отменить любые существующие учетные данные, вызвав метод без аргументов.

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

.force_authenticate(user=None, token=None)

Иногда может потребоваться полностью обойти аутентификацию и заставить все запросы тестового клиента автоматически считаться аутентифицированными.

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

Чтобы отменить аутентификацию последующих запросов, вызовите force_authenticate, установив для пользователя и/или токена значение None .

Проверка CSRF

По умолчанию проверка CSRF не применяется при использовании APIClient . Если вам нужно явным образом включить проверку CSRF, вы можете сделать это, установив флаг force_csrf_checks при создании экземпляра клиента.

Как обычно, проверка CSRF будет применяться только к любым представлениям, прошедшим аутентификацию сеанса.Это означает, что проверка CSRF будет происходить только в том случае, если клиент вошел в систему, вызвав login() .

Среда REST также включает клиент для взаимодействия с вашим приложением с помощью популярной библиотеки Python, запросы . Это может быть полезно, если:

  • Вы предполагаете взаимодействовать с API в основном из другой службы Python и хотите протестировать службу на том же уровне, который увидит клиент.
  • Вы хотите написать тесты таким образом, чтобы их также можно было запускать в промежуточной или реальной среде. (См. раздел "Тесты в реальном времени" ниже.)

Это открывает точно такой же интерфейс, как если бы вы использовали сеанс запросов напрямую.

Обратите внимание, что клиент запросов требует, чтобы вы передавали полные URL-адреса.

RequestsClient и работа с базой данных

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

Если вы используете RequestsClient, вам нужно убедиться, что настройка теста и утверждение результатов выполняются как обычные вызовы API, а не напрямую взаимодействуют с моделями базы данных. Например, вместо того, чтобы проверять, что Customer.objects.count() == 3, вы должны указать конечную точку клиентов и убедиться, что она содержит три записи.

Заголовки и аутентификация

Пользовательские заголовки и учетные данные аутентификации могут быть предоставлены так же, как и при использовании стандартного экземпляра Requests.Session.

Если вы используете SessionAuthentication, вам потребуется включать токен CSRF для любых запросов POST , PUT , PATCH или DELETE.

Вы можете сделать это, следуя тому же алгоритму, что и клиент на основе JavaScript. Сначала сделайте запрос GET, чтобы получить токен CSRF, а затем представьте этот токен в следующем запросе.

Тесты в реальном времени

При осторожном использовании как RequestsClient, так и CoreAPIClient предоставляют возможность писать тестовые сценарии, которые можно запускать либо в процессе разработки, либо непосредственно на промежуточном сервере или в производственной среде.

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

CoreAPIClient позволяет вам взаимодействовать с вашим API с помощью клиентской библиотеки Python coreapi.

Заголовки и аутентификация

Пользовательские заголовки и аутентификация могут использоваться с CoreAPIClient так же, как и с RequestsClient .

Среда REST включает следующие классы тестовых случаев, которые отражают существующие классы тестовых случаев Django, но используют APIClient вместо клиента Django по умолчанию.

  • APISimpleTestCase
  • APITransactionTestCase
  • APITestCase
  • APILiveServerTestCase

Пример

Вы можете использовать любой из классов тестовых наборов REST framework, как и обычные классы тестовых наборов Django. Атрибут self.client будет экземпляром APIClient.

Среда REST также предоставляет класс тестовых примеров для изоляции шаблонов URL для каждого класса. Обратите внимание, что он наследуется от SimpleTestCase Django и, скорее всего, его нужно будет смешать с другим классом тестового примера.

Пример

Проверка данных ответа

При проверке достоверности тестовых ответов часто бывает удобнее проверить данные, на основе которых был создан ответ, а не проверять полностью обработанный ответ.

Например, проще проверить response.data :

Вместо проверки результата синтаксического анализа response.content :

Визуализация ответов

Если вы тестируете представления напрямую с помощью APIRequestFactory , возвращенные ответы еще не будут отображаться, поскольку обработка ответов шаблона выполняется внутренним циклом запроса-ответа Django. Чтобы получить доступ к response.content , вам сначала нужно отобразить ответ.

Установка формата по умолчанию

Формат по умолчанию, используемый для создания тестовых запросов, можно задать с помощью ключа настройки TEST_REQUEST_DEFAULT_FORMAT. Например, чтобы по умолчанию всегда использовать JSON для тестовых запросов вместо стандартных запросов, состоящих из нескольких частей, установите в файле settings.py следующее:

Настройка доступных форматов

Если вам нужно протестировать запросы с использованием чего-то другого, кроме запросов multipart или json, вы можете сделать это, установив параметр TEST_REQUEST_RENDERER_CLASSES.

С этого момента мы действительно начнем рассматривать ядро ​​REST framework. Давайте представим пару основных строительных блоков.

Запрос объектов

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

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

Коды статуса

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

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

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

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

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

Собираем все вместе

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

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

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

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

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

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

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

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

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

Как дела?

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

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

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

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

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

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

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

Наличие доступного для просмотра в Интернете API – это огромное преимущество в плане удобства использования, которое значительно упрощает разработку и использование вашего API. Это также значительно снижает входной барьер для других разработчиков, желающих изучить ваш API и работать с ним.

Дополнительную информацию о функции browsable API и о том, как ее настроить, см. в разделе browsable API.

Что дальше?

В третьей части руководства мы начнем использовать представления на основе классов и увидим, как универсальные представления сокращают объем кода, который нам нужно написать.

Если вы работаете с веб-службой на основе REST . вам следует игнорировать request.POST.

— Малкольм Трединник, группа разработчиков Django

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

request.data возвращает проанализированное содержимое тела запроса. Это похоже на стандартные атрибуты request.POST и request.FILES, за исключением того, что:

Подробнее см. в документации парсеров.

.query_params

request.query_params – это более правильное название синонима для request.GET .

.парсеры

Класс APIView или декоратор @api_view гарантирует, что для этого свойства будет автоматически задан список экземпляров Parser на основе набора parser_classes для представления или на основе параметра DEFAULT_PARSER_CLASSES.

Обычно доступ к этому ресурсу не требуется.

Примечание. Если клиент отправляет искаженный контент, доступ к request.data может вызвать ошибку ParseError . По умолчанию класс APIView среды REST или декоратор @api_view перехватывает ошибку и возвращает ответ 400 Bad Request.

Если клиент отправляет запрос с типом контента, который не может быть проанализирован, возникает исключение UnsupportedMediaType, которое по умолчанию перехватывается и возвращает ответ 415 Unsupported Media Type.

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

.accepted_renderer

Экземпляр средства визуализации, выбранный на этапе согласования содержания.

.accepted_media_type

Строка, представляющая тип мультимедиа, принятый на этапе согласования содержания.

Среда REST обеспечивает гибкую аутентификацию для каждого запроса, что дает вам возможность:

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

request.auth возвращает любой дополнительный контекст аутентификации. Точное поведение request.auth зависит от используемой политики аутентификации, но обычно это может быть экземпляр токена, по которому был аутентифицирован запрос.

Если запрос не прошел проверку подлинности или отсутствует дополнительный контекст, значением request.auth по умолчанию является None .

.аутентификаторы

Класс APIView или декоратор @api_view гарантирует, что для этого свойства будет автоматически задан список экземпляров Authentication на основе набора authentication_classes для представления или на основе параметра DEFAULT_AUTHENTICATORS.

Обычно доступ к этому ресурсу не требуется.

Среда REST поддерживает несколько усовершенствований браузера, таких как браузерные формы PUT , PATCH и DELETE.

.метод

Браузерные формы PUT , PATCH и DELETE прозрачно поддерживаются.

.content_type

Обычно вам не потребуется напрямую обращаться к типу содержимого запроса, так как вы обычно полагаетесь на поведение синтаксического анализа запросов по умолчанию в среде REST.

.поток

request.stream возвращает поток, представляющий содержимое тела запроса.

Как правило, вам не требуется прямой доступ к содержимому запроса, так как обычно вы полагаетесь на стандартное поведение при синтаксическом анализе запроса REST framework.

Общие представления Django REST просто потрясающие. Трудно оправдать написание полного потока вручную, если вы не делаете что-то настолько простое, что не требует проверки или других вещей.

Даже тогда зачем отказываться от просветленного пути? Однако бывают ситуации, когда вы хотите немного изменить request.data в общем представлении, и все станет сложнее.

Проблема: пример с CreateAPIView

CreateAPIView — это конкретное представление для обработки жизненного цикла ответов POST/return в RESTful API. Он принимает запросы JSON POST.

После установки и настройки DRF все, что вам нужно, чтобы начать принимать запросы, — это подкласс CreateAPIView с сериализатором. Пример:

Здесь ContactSerializer — это сериализатор модели DRF для простой модели. Вот сериализатор:

А вот и модель:

Все навороты и свистки, пока внешний интерфейс не отправит объект с точно такими же свойствами, как и в сериализаторе.

Я имею в виду, что перед отправкой POST-запроса из Fetch вы должны создать этот объект:

С FormData легко работать, если у вас есть все входные данные с соответствующими атрибутами имени. Но если вы этого не сделаете, DRF ответит неверным запросом 400. Решение? Небольшая настройка подкласса CreateAPIView.

Когда мы расширяем класс Python, в частности CreateAPIView , мы также можем переопределить унаследованные методы. Если мы перейдем к исходному CreateAPIView, мы увидим метод публикации:

Кажется, это хорошее место для изменения запроса .

AttributeError: этот экземпляр QueryDict неизменяем

Когда платформа Django REST получает запрос, request.data является точкой входа для вашего файла . данные. Полезная нагрузка JSON из вашего внешнего интерфейса попадет туда.

Представим, что коллега не знает точную форму объекта запроса и вместо отправки этого:

Допустим также, что вы воспроизвели ошибку в трех разных интерфейсах, и нет простого способа вернуться обратно.

Как мы можем преобразовать этот объект JSON в request.data, чтобы избежать ошибки 400? Легче сделать, чем сказать! Просто переопределите метод post и испортите данные:

Если бы это было так просто! Если мы запустим это представление, мы получим AttributeError: Этот экземпляр QueryDict неизменяем. Сюрприз!

Единственный способ изменить его — скопировать объект и изменить копию.Но нет никакого способа заменить request.data вашим собственным объектом, потому что на этом этапе request тоже неизменяем.

Итак, где мы перехватываем и обмениваем request.data ?

ПРИМЕЧАНИЕ: если вы хотите протестировать это представление, ознакомьтесь с DRF: тестирование запросов POST.

get_serializer на помощь

При создании подкласса CreateAPIView мы получаем доступ ко всем методам, определенным в CreateModelMixin и GenericAPIView:

Вот диаграмма UML от Pycharm:

CreateModelMixin довольно прост и состоит из трех методов: create , Perform_create , get_success_headers .

create особенно интересен тем, что он перенаправляет request.data другому методу с именем get_serializer . Вот соответствующий код:

get_serializer не находится непосредственно в CreateModelMixin, он находится в GenericAPIView:

Бинго! Что, если мы переопределим этот метод в нашем представлении для перехвата и изменения kwargs["data"] ?

Перехват request.data в нужном месте

На наш взгляд, мы можем заменить get_serializer нашей собственной версией:

Если в request.data есть неправильные поля, мы делаем копию, изменяем поля и помещаем копию в аргумент ключевого слова данных:

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

ПРИМЕЧАНИЕ: в примере я использую оператор warlus из Python 3.8.

Объект запроса в среде Django REST неизменяем, поэтому request.data . Чтобы изменить полезную нагрузку, мы можем сделать копию, но нет возможности поменять местами исходный объект с нашей копией, по крайней мере, в методе публикации.

Пользовательское переопределение get_serializer из общего представления DRF может решить проблему более простым способом.

Спасибо за чтение!

БУДЬТЕ В ОБНОВЛЕНИИ

Узнавайте первыми, когда я публикую новые материалы.

КУРСЫ И КНИГИ

Развязанный Джанго

Рефакторинг для React Hooks

Маленькая книга по JavaScript

Привет! Я Валентино! Я независимый консультант с большим опытом работы в ИТ-индустрии. Последние годы я работал консультантом по внешнему интерфейсу, предоставляя советы и помощь, тренируя и обучая JavaScript и React. Свяжитесь с нами!

Читайте также: