Как подключить Browsable API в DRF

В этом туториале вы подключите удобный интерфейс для API-запросов из браузера к сайту для продажи вин.

img

1. Разверните исходный проект

Для того, чтобы материал туториала усвоился лучше, очень советуем проделать все его шаги на своём компьютере.

Для этого скачайте этот репозиторий и разверните по инструкции из README.md.

Замените базу данных на готовую, заполненную винами: ссылка на БД.

По ссылке 127.0.0.1:8000/api/wine_list/ вы получите JSON-ответ от сервера:

img

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/ вы видите страничку авторизации:

img

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, что вы делали запрос из браузера и выдаст ответ в приятном виде:

img

При этом из консоли запрос по-прежнему в 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

Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.

Переходите на страницу учебных модулей «Девмана» и выбирайте тему.