JavaRush /Курси /Модуль 3: Django /Налаштування маршрутизації для API

Налаштування маршрутизації для API

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

Якщо подивитися на роботу веб-додатків загалом, маршрутизація визначає, який обробник буде викликаний на конкретний запит. Наприклад, запит GET /articles/1/ має потрапити на обробник, який поверне дані статті з ID = 1. Ось де маршрутизація вступає в гру: вона "прокладає шлях" між URL і вашим кодом.

У Django REST Framework маршрутизація бере ці принципи і додає зручності: ви можете використовувати як стандартні функції path() і re_path(), так і спеціальні маршрутизатори (Routers), які виконують частину роботи за нас. Розберемося у всьому по порядку.

Основи маршрутизації: зв'язок URL з обробником

Почнемо з базового підходу і будемо використовувати APIView. Наприклад, припустимо, що у нас є простий додаток з моделлю Article. Ось приклад:

# models.py
from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()

    def __str__(self):
        return self.title

Ми хочемо створити API, щоб отримувати список усіх статей і додавати нові. Для початку створимо два методи всередині представлення APIView:

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Article
from .serializers import ArticleSerializer

class ArticleListCreateAPIView(APIView):
    def get(self, request):
        articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data)

    def post(self, request):
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Тепер додамо маршрути для підключення до цих методів:

# urls.py
from django.urls import path
from .views import ArticleListCreateAPIView

urlpatterns = [
    path('articles/', ArticleListCreateAPIView.as_view(), name='article-list-create'),
]

Зараз наші запити потраплять до ArticleListCreateAPIView, і все запрацює. Але при збільшенні кількості представлень (наприклад, додаванні обробки GET /articles/<id>/) код маршрутизації стане громіздким. Щоб вирішити цю проблему, ми можемо використовувати ViewSet.

Використання ViewSet для спрощення маршрутизації

Замість того щоб прописувати маршрути для кожного методу, DRF пропонує створити ViewSet, який об'єднує логіку для однотипних операцій. Ось приклад ViewSet для нашого API:

# views.py
from rest_framework.viewsets import ModelViewSet

class ArticleViewSet(ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

Зверніть увагу, як лаконічно оголошена ця структура: DRF сам знає, що ViewSet повинен підтримувати GET, POST, PUT, DELETE і т.д.

Тепер переходимо до маршрутів. Замість ручного прописування використовуємо маршрутизатор:

# urls.py
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet

router = DefaultRouter()
router.register(r'articles', ArticleViewSet, basename='article')

urlpatterns = router.urls

Завдяки цьому ми отримуємо маршрути для всіх CRUD-операцій автоматично:

  • GET /articles/
  • POST /articles/
  • GET /articles/<id>/
  • PUT /articles/<id>/
  • DELETE /articles/<id>/

Легко помітити, наскільки це спрощує життя.

DefaultRouter та види маршрутизаторів

  • DefaultRouter — це стандартний інструмент для автоматичної генерації маршрутів. Він створює маршрути для списку, деталей і, що зручно, додає маршрут до кореневого списку API. Це корисно для початкового налаштування, але якщо у вас є специфічні вимоги, доведеться все ж таки використовувати кастомізації.

  • SimpleRouter. Якщо кореневий список API не потрібен, ви можете використовувати SimpleRouter замість DefaultRouter. Логіка роботи залишається такою ж, але він не додає "зайвих" маршрутів.

  • Custom Router. Для унікальних вимог можна взагалі створити свій маршрутизатор. DRF дозволяє перевизначити його поведінку шляхом наслідування від BaseRouter. Але в рамках більшості проєктів важливо освоїти базові варіанти.

Комбінування маршрутів вручну і за допомогою Router

Іноді одні маршрути зручніше описувати явно, а інші підключати через маршрутизатор. Розглянемо такий випадок. Припустимо, у нас є ще один ендпоінт, який повертає "популярні статті". Ми можемо зробити наступне:

# views.py
from rest_framework.decorators import action
from rest_framework.response import Response

class ArticleViewSet(ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

    @action(detail=False, methods=['get'])
    def popular(self, request):
        popular_articles = Article.objects.filter(is_popular=True)
        serializer = self.get_serializer(popular_articles, many=True)
        return Response(serializer.data)

У urls.py це виглядає так:

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet

router = DefaultRouter()
router.register(r'articles', ArticleViewSet, basename='article')

urlpatterns = [
    path('', include(router.urls)),
    path('articles/popular/', ArticleViewSet.as_view({'get': 'popular'})),
]

Тепер запит GET /articles/popular/ поверне популярні статті.

Особливості та типові помилки

Коли працюєш з маршрутизацією, виникає ряд питань і потенційне джерело помилок:

  1. Помилка "NoReverseMatch". Якщо ви реєструєте маршрути через DefaultRouter, переконайтеся, що вказали коректний basename.
  2. Перевизначення методів ViewSet. Якщо вам потрібно визначити кастомну поведінку (наприклад, дозволяти видалення тільки адміністраторам), використовуйте методи ViewSet.
  3. Проблеми з підключенням маршрутизатора. Не забудьте про правильний імпорт і підключення маршрутів за допомогою include(router.urls).

Практичне завдання

Тепер, коли ви знаєте, як використовувати маршрути та маршрутизатори, створіть API для управління завданнями в додатку todo. Модель завдання повинна містити поля:

  • title (назва завдання),
  • description (опис),
  • is_done (статус виконання).

Реалізуйте API для:

  1. Списку завдань,
  2. Додавання нового завдання,
  3. Редагування завдання,
  4. Видалення завдання,
  5. Маршрут /tasks/completed/ для отримання виконаних завдань.

Переконайтеся, що ваш API протестований за допомогою браузера або Postman.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ