Как подключить Browsable API в DRF
В этом туториале вы подключите удобный интерфейс для API-запросов из браузера к сайту для продажи вин.
1. Разверните исходный проект
Для того, чтобы материал туториала усвоился лучше, очень советуем проделать все его шаги на своём компьютере.
Для этого скачайте этот репозиторий и разверните по инструкции из README.md
.
Замените базу данных на готовую, заполненную винами: ссылка на БД.
По ссылке 127.0.0.1:8000/api/wine_list/ вы получите JSON-ответ от сервера:
2. Подключите к проекту Django REST Framework
Browserable API — это фича библиотеки Django REST Framework
Официальная инструкция по установке
Установите модуль:
# pip install djangorestframework
Добавьте rest_framework
в список INSTALLED_APPS
в файле wines_api/settings.py
:
INSTALLED_APPS = [
...
'rest_framework',
]
Добавьте странички из DRF в wines_api/urls.py
:
urlpatterns = [
...
path('api-auth/', include('rest_framework.urls'))
]
У вас получилось установить DRF, если по адресу 127.0.0.1:8000/api-auth/login/ вы видите страничку авторизации:
3. Подключите DRF к API-ручке
DRF готов дать вам свои фичи, но для этого ему нужно чтобы вы добавили вашим вьюхам декоратор @api_view
, если ваши вьюхи — функции или класс APIView
, если вы используете Class Based Views:
До:
def wine_list(request):
wines = models.Wine.objects.all()
...
После:
from rest_framework.decorators import api_view
@api_view(['GET'])
def wine_list(request):
wines = models.Wine.objects.all()
...
Теперь, если к вам пришлют POST-запрос на эту API-ручку, то отправитель автоматически получит ответ 405 Method Not Allowed
. Откройте новую консоль, запустите python
и попробуйте сделать такой запрос:
import requests
requests.post('http://127.0.0.1:8000/api/wine_list/').text
Вот что вы получите в ответ: {"detail":"Method \\"POST\\" not allowed."}
Также изменился сам объект request
. Если раньше вы брали данные запроса так: request.GET
или request.POST
, то теперь больше нет нужды в таком условии:
if request.method == 'GET':
do_something()
elif request.method == 'POST':
do_something_else()
Теперь все данные можно получить одним способом: request.data
.
Также больше нет нужды в преобразовании типов данных, таких как json.loads(request.data)
. DRF сам понимает тип данных благодаря заголовку Content-Type
и сразу вернёт словарь, если в этом заголовке указано application/json
4. Добавьте Response-объект из DRF
Также DRF предоставляет свой Response
-объект. Теперь нет нужды передавать HTTPResponse отдельно, а JSONResponse отдельно. Стоит пользоваться одним Response
-объектом в любой ситуации:
До:
@api_view(['GET'])
def wine_list(request):
wines = models.Wine.objects.all()
...
return JsonResponse(dumped_wines, safe=False, json_dumps_params={
'ensure_ascii': False,
'indent': 4,
})
После:
from rest_framework.response import Response
@api_view(['GET'])
def wine_list(request):
wines = models.Wine.objects.all()
...
return Response(dumped_wines)
После этого Response будет сам определять в каком формате отдавать данные по заголовку Accept
. Этот заголовок говорит о том в каком формате ожидается ответ. Если сделать запрос из браузера, то в этом заголовке будет значение text/html
.
Теперь если вы зайдёте на страничку 127.0.0.1:8000/api/wine_list/ вы увидите Browserable API, т.к. DRF автоматически поймёт по заголовку Accept
, что вы делали запрос из браузера и выдаст ответ в приятном виде:
При этом из консоли запрос по-прежнему в JSON-формате:
import requests
requests.get('http://127.0.0.1:8000/api/wine_list/').json()
В ответ вы получите по-прежнему JSON:
[{'category': 'Белое вино', 'title': 'Белая леди', 'sort_of_grape': 'Дамский пальчик', 'price': 399, 'by_stock': True}, {'category': 'Белое вино', 'title': 'Ркацители', 'sort_of_grape': 'Ркацители', 'price': 499, 'by_stock': False}, {'category': 'Белое вино', 'title': 'Кокур', 'sort_of_grape': 'Кокур', 'price': 450, 'by_stock': False}, {'category': 'Красное вино', 'title': 'Черный лекарь', 'sort_of_grape': 'Качич', 'price': 399, 'by_stock': False}, {'category': 'Красное вино', 'title': 'Хванчкара', 'sort_of_grape': 'Александраули', 'price': 550, 'by_stock': False}, {'category': 'Красное вино', 'title': 'Киндзмараули', 'sort_of_grape': 'Саперави', 'price': 550, 'by_stock': True}]
Теперь добавим дополнительный заголовок:
requests.get('http://127.0.0.1:8000/api/wine_list/', headers={'Accept': 'text/html'}).text
В ответ прилетит уже HTML:
<!DOCTYPE html>\n<html>\n <head>\n \n\n \n <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>\n <meta name="robots" content="NONE,NOARCHIVE" />\n \n\n <title>Wine List – Django REST framework</title>
...
Попробуйте бесплатные уроки по Python
Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.
Переходите на страницу учебных модулей «Девмана» и выбирайте тему.