Представления UpdateAPIView и RetrieveUpdateDestroyAPIView

Курс по Django: https://stepik.org/a/183363

Смотреть материал на YouTube

На предыдущем занятии мы с вами вышли на более высокий (абстрактный) уровень описания API на базе классов ModelSerializer и ListCreateAPIView. Однако, для повторения функционала нашего прежнего класса представления WomenAPIView, необходимо обеспечить изменение конкретной записи. Для этого можно воспользоваться еще одним высокоуровневым базовым классом UpdateAPIView, следующим образом:

class WomenAPIUpdate(generics.UpdateAPIView):
    queryset = Women.objects.all()
    serializer_class = WomenSerializer

Здесь определили новый класс представления, в котором прописали два знакомых нам атрибута: queryset и serializer_class для указания класса-сериализатора. Атрибут queryset отвечает за то, какие данные следует вернуть клиенту на соответствующий API-запрос. На первый взгляд кажется, что мы выбираем все записи и их список будет отправляться клиенту. Однако, всегда следует помнить, что запросы в Django по умолчанию ленивые, т.е. выполняются не сразу, а в момент, когда происходит первая попытка обращения к ним. Благодаря этому, запрос для коллекции queryset может быть модифицирован в базовом классе UpdateAPIView, прежде чем будут получены какие-либо записи. В частности, здесь клиенту возвращается одна запись, которая была изменена.

Свяжем теперь это представление с маршрутом (в файле drfsite/urls.py):

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/womenlist/', WomenAPIList.as_view()),
    path('api/v1/womenlist/<int:pk>/', WomenAPIUpdate.as_view()),
]

И посмотрим, как это будет работать. Запустим тестовый веб-сервер, перейдем в программу Postman и выполним PUT-запрос на адрес:

http://127.0.0.1:8000/api/v1/womenlist/6/

Здесь 6 – это идентификатор изменяемой записи, а JSON-данные для отправки определим, следующим образом:

{
    "title": "Sergei Balakirev",
    "content": "Известный программист и преподаватель 21-го века. Его наследие актуально и живо и по сей день.",
    "cat": 2
}

Нажимаем на отправку и видим, что запись с id=6 изменилась на переданные нами данные.

В итоге, мы полностью повторили функционал прежнего класса-представления WomenAPIView и его можно теперь убрать. Как видите, текст программы стал гораздо короче и понятнее.

Класс RetrieveUpdateDestroyAPIView

Часто при разработке API требуется создавать, читать, менять и удалять отдельные записи. Весть этот функционал принято еще называть аббревиатурой CRUD (от англ. Create, Read, Update, Delete). Так как это все стандартные действия, то для них был создан специальный класс представления:

RetrieveUpdateDestroyAPIView

Давайте определим еще один класс представления, унаследованный от RetrieveUpdateDestroyAPIView:

class WomenAPIDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Women.objects.all()
    serializer_class = WomenSerializer

и свяжем его со следующим URL:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/womenlist/', WomenAPIList.as_view()),
    path('api/v1/womenlist/<int:pk>/', WomenAPIUpdate.as_view()),
    path('api/v1/womendetail/<int:pk>/', WomenAPIDetailView.as_view()),
]

Обратите внимание на параметр pk URL-адреса. Это имя, которое используется по умолчанию и фреймворком Django и Django REST для извлечения записи с id равным pk. Поэтому изначально, если нигде ничего не переопределено, то следует в маршруте прописывать именно это имя параметра. Далее, оно автоматически будет выделено из URL-запроса и прочитана соответствующая запись из таблицы БД. Фреймворк эти действия делает на автомате.

В принципе, у нас все готово, давайте протестируем наш новый функционал. Запустим веб-сервер:

python manage.py runserver

В браузере укажем URL:

http://127.0.0.1:8000/api/v1/womendetail/5/

и увидим следующую страницу, которая автоматически генерируется DRF (или можно воспользоваться программой Postman):

Сейчас мы видим, что запись с id=5 успешно была прочитана и отображена. Давайте ее попробуем изменить. В форме ниже запишем данные для PUT-запроса:

И после нажатия на кнопку «PUT» данные успешно были изменены.

Теперь удалим эту запись. Нажмем на кнопку «DELETE» и после выполнения запроса, видим, что запись удалена. Если мы обновим эту страницу, т.е. попробуем получить из БД удаленную запись с id=5, то получим JSON-строку:

{"detail": "Страница не найдена."}

Вот так, легко и просто мы создали API по работе с одной конкретной записью в БД.

Если бы мы создавали свой API с нуля во фреймворке Django (без использования DRF), то нам бы понадобилось писать гораздо больший код, который в дальнейшем было бы поддерживать сложнее, чем код на DRF. Вот наглядное преимущество Django REST.

Отключение браузерного API

Сразу хочу отметить, что после отладки API мы можем отключить формирование браузерной формы. Об этом написано в официальной документации на странице API Guide / Renderers:

https://www.django-rest-framework.org/api-guide/renderers/

В частности, по умолчанию применяются следующие настройки:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ]
}

Здесь указано, что используется JSON для обмена информацией между клиентами и сервером, а также подключается браузерное API. Например, она появляется по запросу:

http://127.0.0.1:8000/api/v1/womenlist/

Давайте уберем строчку с BrowsableAPIRenderer и в файле drfsite/settings.py определим эту коллекцию, следующим образом:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ]
}

Теперь, при обновлении страницы браузера, мы увидим «сырой» JSON-ответ от сервера, а не HTML-документ с данными и формой обратной связи с сервером.

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

Курс по Django: https://stepik.org/a/183363