Класс ModelSerializer и представление ListCreateAPIView

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

На предыдущем занятии мы с вами определили сериализатор на основе базового класса Serializer для получения данных в JSON-формате, добавления и изменения уже существующих в таблице БД. Для этого была использована модель Women и ORM Django. То есть, наш сериализатор напрямую связан с моделью таблицы БД. Это распространенная схема, поэтому для нее существует специальный класс сериализатора:

ModelSerializer

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

Укажем в качестве базового класса ModelSerializer для нашего сериализатора WomenSerializer и тогда уже нет необходимости вручную прописывать атрибуты для связи с соответствующими атрибутами модели, а также методы create() и update(). А вместо всего этого пропишем вложенный класс Meta:

class WomenSerializer(serializers.ModelSerializer):
    class Meta:
        model = Women
        fields = ("title", "content", "cat")

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

Все! Если сейчас запустить тестовый веб-сервер:

python manage.py runserver

перейти в программу Postman для имитации клиентских запросов, выбрать GET-запрос для адреса:

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

то получим данные в формате JSON по, указанным в сериализаторе, полям title, content, cat.

Также будут работать и остальные запросы POST:

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

и PUT.

Если в сериализаторе мы собираемся работать со всеми полями модели, то в классе Meta можно прописать:

class WomenSerializer(serializers.ModelSerializer):
    class Meta:
        model = Women
        fields = "__all__"

И, теперь, при GET-запросе, мы будем получать список по всем полям таблицы women.

Некоторых из вас сейчас может обуять праведный гнев, готовых со сверкающим взглядом заявить: какого «фига» мы на прошлых занятиях сразу не воспользовались этим базовым классом и вручную прописывали всю реализацию по работе с моделями БД? Обычно, кстати, при обучении так и делают, сразу показывают вариант с классом ModelSerializer, не объясняя подробно, что скрывается под капотом. А знать всю поднаготную сериализаторов, на мой взгляд, необходимо, т.к. в крупных проектах, зачастую, приходится создавать свои собственные сериализаторы на базе класса Serializer или других классов-сериализаторов. Поэтому на прошлых занятиях я подробно показывал изнанку этого процесса.

Класс ListCreateAPIView

Но, раз разработчики Django REST Framework упростили определение сериализаторов, связанных с моделью, то, наверное, аналогичное упрощение должно быть и для классов представлений? И, действительно, в DRF существует несколько предопределенных базовых классов, о которых подробно можно почитать на следующей странице официальной документации:

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

Они, следующие:

  • CreateAPIView – создание данных по POST-запросу;
  • ListAPIView – чтение списка данных по GET-запросу;
  • RetrieveAPIView – чтение конкретных данных (записи) по GET-запросу;
  • DestroyAPIView – удаление данных (записи) по DELETE-запросу;
  • UpdateAPIView – изменение записи по PUT- или PATCH-запросу;
  • ListCreateAPIView – для чтения (по GET-запросу) и создания списка данных (по POST-запросу);
  • RetrieveUpdateAPIView – чтение и изменение отдельной записи (GET-, PUT- и PATCH-запросы);
  • RetrieveDestroyAPIView – чтение (GET-запрос) и удаление (DELETE-запрос) отдельной записи;
  • RetrieveUpdateDestroyAPIView – чтение, изменение и добавление отдельной записи (GET-, PUT-, PATCH- и DELETE-запросы).

Применяются все эти базовые классы похожим образом, поэтому мы рассмотрим примеры только некоторых из них.

У нас в программе реализуется GET-запрос, по которому возвращается список записей в JSON-формате. Очевидно, эту функциональность поддерживают классы ListAPIView и ListCreateAPIView. Мы выберем второй, чтобы сразу обеспечить возможность добавления данных.

Определим дочерний класс представления (в файле women/views.py) на базе ListCreateAPIView, следующим образом:

class WomenAPIList(generics. ListCreateAPIView):
    queryset = Women.objects.all()
    serializer_class = WomenSerializer

Здесь атрибут queryset должен ссылаться на словарь с данными для их последующей обработки (сериализации), а атрибут serializer_class – на класс-сериализатор, который будет применяться к коллекции queryset.

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

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

Все, запускаем тестовый веб-сервер, переходим в программу Postman и выполняем GET-запрос для URL:

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

видим тот же список с данными в JSON-формате. При этом в классе WomenAPIList нам потребовалось прописать всего две строчки кода, благодаря использованию базового класса ListCreateAPIView.

Если посмотреть на реализацию класса ListCreateAPIView, то увидим, что он, в свою очередь, наследуется от двух классов миксинов: ListModelMixin и CreateModelMixin, а также общего класса GenericAPIView. Вот, кстати, пример использования множественного наследования в Python. Здесь классы миксинов описывают базовый функционал по работе с моделями. Давайте перейдем в ListModelMixin. Видим метод list(), который читает данные из таблицы БД и прогоняет их через сериализатор, формируя на выходе JSON-ответ в виде списка данных. Примерно то же самое мы прописывали вручную, когда создавали представление с нуля на основе класса APIView. Ну а в классе ListCreateAPIView реализованы два метода:

  • get() – для обработки GET-запроса;
  • post() – для обработки POST-запроса.

В целом все относительно просто и эффективно. Это, кстати, хороший пример использования ООП для упрощения написания программ. Советую внимательно его изучить и применять подобные элементы в своих программах.

Так как класс ListCreateAPIView поддерживает метод POST, то мы также можем добавлять данные, отправленные по POST-запросу в JSON-формате. Внизу страницы имеется форма для отправки данных методом POST для добавления их в БД:

Такая форма автоматически появляется, если класс представления поддерживает создание и изменение данных.

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

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