JavaRush /Курси /Модуль 3: Django /Використання ModelViewSet

Використання ModelViewSet

Модуль 3: Django
Рівень 20 , Лекція 3
Відкрита

ModelViewSet – це один із найзручніших і найчастіше використовуваних типів ViewSet у DRF. Він призначений для роботи з моделями Django і автоматично надає повний набір операцій CRUD (Create, Read, Update, Delete). По суті, він вже містить всю необхідну логіку, тож вам залишиться лише підключити модель і серіалізатор.

Чому ModelViewSet — це зручно?

  • Економія коду: тобі не потрібно вручну прописувати методи для CRUD-операцій. Все вже реалізовано, ти просто підключаєш модель і серіалізатор.
  • Стандартизованість: код стає більш уніфікованим, що полегшує супровід.
  • Гнучкість: якщо раптом потрібно перевизначити стандартну поведінку якогось методу, це легко зробити.
  • Швидкість розробки: чим менше коду, тим швидше розробка і менше ймовірність помилок.

Приблизно як з хорошою бібліотекою JavaScript: «просто підключи, і все працює (майже)».

Як це працює?

ModelViewSet наслідується від класу GenericViewSet і змішує в собі міксіни, такі як CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin і ListModelMixin. Саме завдяки цим міксінам він надає стандартні CRUD-операції.

Основний функціонал, що надається ModelViewSet:

  1. GET /items/ – повертає список об'єктів.
  2. GET /items/<id>/ – повертає об'єкт із вказаним ID.
  3. POST /items/ – створює новий об'єкт.
  4. PUT /items/<id>/ – оновлює об'єкт із вказаним ID.
  5. PATCH /items/<id>/ – частково оновлює об'єкт.
  6. DELETE /items/<id>/ – видаляє об'єкт із вказаним ID.

Реалізація ModelViewSet

Тепер давайте перейдемо від теорії до практики. Ми створимо ModelViewSet для управління простою моделлю — наприклад, моделлю задач для ToDo-додатку.

  1. Створимо модель Task

Спочатку додамо нову модель у наш проєкт, якщо вона ще не була створена.

from django.db import models

class Task(models.Model):
    title = models.CharField(max_length=255)
    description = models.TextField(blank=True)
    completed = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title

Не забудьте виконати міграції:

python manage.py makemigrations
python manage.py migrate
  1. Створимо серіалізатор для моделі

Для роботи ModelViewSet потрібен серіалізатор. Створимо простий TaskSerializer.

from rest_framework import serializers
from .models import Task

class TaskSerializer(serializers.ModelSerializer):
    class Meta:
        model = Task
        fields = '__all__'

Серіалізатор ModelSerializer автоматично генерує поля на основі нашої моделі, тож працювати з ним дуже зручно.

  1. Створимо ModelViewSet

Тепер створимо сам ViewSet для моделі Task. Це буде так само просто, як зробити каву з капсули (якщо у вас є кавомашина).

from rest_framework.viewsets import ModelViewSet
from .models import Task
from .serializers import TaskSerializer

class TaskViewSet(ModelViewSet):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

Зверніть увагу:

  • queryset — це набір об'єктів, з якими буде працювати наш ViewSet.
  • serializer_class — вказівка серіалізатора для обробки даних.
  1. Підключимо маршрутизацію з Router

Налаштування маршрутів для ViewSet виконується через Router. Це робить наше життя ще простішим.

Додамо маршрути в urls.py:

from rest_framework.routers import DefaultRouter
from .views import TaskViewSet

router = DefaultRouter()
router.register(r'tasks', TaskViewSet, basename='task')

urlpatterns = router.urls

Тепер DRF автоматично згенерує маршрути для роботи із задачами, такі як:

  • GET /tasks/
  • POST /tasks/
  • GET /tasks/{id}/
  • PUT /tasks/{id}/
  • DELETE /tasks/{id}/

Спробуйте відвідати /tasks/ у браузері або в Postman. У вас з'явиться готовий API для управління задачами. Це, можна сказати, магія DRF.

Додаткові можливості ModelViewSet

Все це добре, але що, якщо ви захочете модифікувати стандартну поведінку? Наприклад, додати перевірку перед видаленням задачі або відправляти лист після її створення? Вам доступні наступні методи для перевизначення:

  • list() — для обробки запиту на отримання списку об'єктів (GET /tasks/).
  • retrieve() — для обробки запиту на отримання одного об'єкта (GET /tasks/<id>/).
  • create() — для обробки запиту на створення об'єкта (POST /tasks/).
  • update() — для обробки запиту на оновлення об'єкта (PUT/PATCH /tasks/<id>/).
  • destroy() — для обробки запиту на видалення об'єкта (DELETE /tasks/<id>/).

Приклад перевизначення методу destroy

Давайте додамо логіку, яка забороняє видаляти задачі, якщо вони завершені.

from rest_framework.response import Response
from rest_framework import status

class TaskViewSet(ModelViewSet):
    queryset = Task.objects.all()
    serializer_class = TaskSerializer

    def destroy(self, request, *args, **kwargs):
        task = self.get_object()
        if task.completed:
            return Response(
                {"error": "Не можна видаляти завершені задачі!"},
                status=status.HTTP_400_BAD_REQUEST
            )
        return super().destroy(request, *args, **kwargs)

Тепер при спробі видалити завершену задачу API поверне помилку.

Коли використовувати ModelViewSet?

ModelViewSet ідеально підходить для стандартного CRUD-функціоналу, коли тобі потрібно швидко налаштувати API для роботи з моделлю. Однак, якщо у тебе нестандартна логіка, багато кастомних дій, або ти хочеш повністю контролювати процес, краще використовувати APIView або GenericViewSet.

Практичний приклад

Спробуйте реалізувати ModelViewSet для іншої моделі у вашому проєкті. Наприклад, якщо у вас є модель користувачів або подій, налаштуйте для неї ViewSet і перевірте роботу через Postman. Як перевірити?

  1. Створіть кілька завдань через POST-запити.
  2. Отримайте список усіх завдань через GET /tasks/.
  3. Завершіть одне із завдань (PATCH /tasks/1/ з параметром completed=true).
  4. Спробуйте видалити завершене завдання і переконайтеся, що сервер повертає помилку.

Типові помилки та їх вирішення

Іноді ти можеш зіткнутися з такими помилками:

  1. Помилка маршрутизації: якщо ти додав ViewSet до маршрутизатора неправильно, переконайся, що використовував router.register() правильно.
  2. Помилка в серіалізаторі: якщо якісь поля відсутні або не серіалізуються, перевір налаштування твого ModelSerializer.
  3. Проблеми з перевизначенням методів: переконайся, що викликаєш super() у перевизначених методах, щоб не втратити стандартну логіку.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ