Django REST Framework: быстрое начало работы

Оглавление

TL;DR Django REST Framework

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

Введение в REST-фреймворк Django

Django REST Framework - это как Django для RESTful API. Он предоставляет столько возможностей из коробки, что, просто установив и подключив его к Django, вы получаете тонну функциональности без необходимости писать много кода вообще. Для больших и сложных проектов это огромное облегчение для тех, кто занимается поддержкой такого кода.

Django REST Framework поставляется с сериализаторами, которые могут напрямую заменить Django Forms для проверки и создания объектов на основе API, общими классами представлений для быстрого запуска конечных точек API, а также автоматически генерируемым браузерным API для любого из используемых вами представлений Django REST Framework.

Это лишь некоторые из замечательных возможностей, которые предоставляет Django REST Framework, и, как и в случае с Django и любым другим пакетом Python, вы можете взять те части, которые вам нужны, а остальное оставить в покое, что позволит вам легко справиться с такой задачей, как преобразование существующих API в Django REST Framework без необходимости изучения всего фреймворка.

Давайте вкратце рассмотрим некоторые моменты, которые делают Django REST Framework столь мощным.

Сериализаторы

Когда я только начал работать с Django REST Framework, у меня уже были собственные API, построенные с использованием Django Generic Views, и я испытывал трудности с сериализацией сложных данных. Импорт и использование сериализаторов Django REST Framework избавили меня от этой головной боли. Существует несколько различных сериализаторов, которые можно использовать, и каждый из них можно настраивать. Из коробки сериализаторы легко справляются со сложными экземплярами моделей Django, а API для использования сериализаторов интуитивно понятен и хорошо документирован.

Сериализаторы Django REST Framework настолько похожи на формы Django, что у вас не должно возникнуть проблем с их освоением. Давайте рассмотрим `ModelSerializer` из Django REST Framework и сравним его с Django ModelForm:

"""
Forms for Character model
"""
from django import forms

from characters.models import Character


class CharacterCreateView(forms.ModelForm):
    class Meta:
        model = Character
        fields = ('name', 'description', 'profession', 'mentor', 'team', 'type',)


class CharacterUpdateView(forms.ModelForm):
    class Meta:
        model = Character
        fields = ('name', 'description', 'profession', 'mentor', 'team', 'type',)
"""
Serializers for Character model
"""

from rest_framework import serializers

from characters.models import Character


class CharacterSerializer(serializers.ModelSerializer):
    mentor = serializers.StringRelatedField()
    team = serializers.StringRelatedField()
    random_line = serializers.SerializerMethodField()

    @staticmethod
    def get_random_line(obj):
        return obj.get_line()

    class Meta:
        model = Character
        fields = (
            'name', 'description', 'profession', 'mentor', 'team', 'type', 'random_line',
        )

Вы видите, что определение практически идентично. Различия в этом простом примере заключаются в наличии StringRelatedField полей и get_random_line метода на CharacterSerializer. Эти дополнительные элементы используются для добавления дополнительной информации в сериализованный вывод.

<1>> принимает StringRelatedField связанную модель и выводит ее __str__ представление при сериализации, а get_random_line вызывает метод модели и добавляет его в сериализованный вывод. Сериализаторы DRF позволяют настраивать, добавлять и исключать из сериализованного вывода любые данные по своему усмотрению.

Подобно Django ModelForms, ModelSerializer также предоставляет метод create и update, так что вы можете создавать и обновлять экземпляры моделей через ваш сериализатор и конечные точки API.

Еще одной мощной особенностью сериализаторов Django REST Framework является то, что помимо просто обработки форм, они могут использоваться для сериализации данных в _bulk_. Вы можете сериализовать целые наборы запросов в JSON без каких-либо модификаций.

Виды

Django REST Framework предоставляет общие представления на основе классов, которые можно просто использовать "из коробки". Эти представления будут автоматически создавать для вас как просматриваемый API, так и JSON-формат API.

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

Для перечисления, создания, извлечения, уничтожения и обновления предусмотрены представления. Все они могут использоваться по отдельности как представления, основанные на классах, и подключаться к любому URL-маршруту, или же их части могут быть "смешаны" вместе, чтобы включить или исключить определенные действия или функциональность конечной точки из ваших представлений.

Однако для большинства ваших нужд Django REST Framework оказал нам услугу, объединив конечные точки, которые сочетаются друг с другом на основе спецификации REST, предоставив нам ListCreateAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView и, наконец, RetrieveUpdateDestroyAPIView.

Для того чтобы сделать еще один шаг вперед, Django REST Framework предоставляет ViewSets, которые представляют собой единые классы представлений, обеспечивающие всю функциональность представления для данной конечной точки. Это пять конечных точек, не говоря уже о встроенном API для просмотра, и все это бесплатно. Это великолепно.

Таким образом, если вы используете общие представления, основанные на классах Django, вы сможете создать практически идентичные представления, используя представления, основанные на классах DRF, для создания вашего API тем же способом.

Самое приятное, что все эти представления могут быть основаны на классах Django Model, так что при изменении модели данных конечные точки будут оставаться актуальными, и вам не придется их поддерживать.

Просмотровый API

Я уже несколько раз упоминал о browsable API, потому что это такой подарок. Наличие просматриваемого API может служить как документацией, так и средством поиска неисправностей и дымового тестирования API. Отсутствие необходимости писать документацию экономит массу времени.

Просмотровый API также можно настраивать, если вам не нравится стандартное форматирование или стиль создаваемых страниц. Существуют сторонние инструменты, которые привлекают большое внимание тем, что делают то же самое, что и API с возможностью просмотра; они позволяют запрашивать конечные точки API и визуализировать данные в чистом и даже красивом виде. В REST-фреймворке Django это уже реализовано!

URLs

То, как DRF работает с URL-адресами, опять же смоделировано по образцу самого Django. Когда вы добавляете представление в свой проект, вам необходимо добавить URL-маршрут для этого представления. DRF предоставляет несколько замечательных утилит для работы с комбинированными классами представлений, поэтому маршруты создаются автоматически. Используя классы провайдера Router, ваши представления будут подключаться и функционировать так, как ожидается, без особых усилий с вашей стороны

from rest_framework import routers

router = routers.SimpleRouter()
router.register(r'users', UserViewSet)
router.register(r'accounts', AccountViewSet)
urlpatterns = router.urls

Разумеется, вы можете подключать URL к представлениям точно так же, как вы подключаете представления Django к URL-маршрутам:

from django.urls import path, include

urlpatterns = [
    path('<int:pk>', views.CharacterDetailView.as_view(), name='get_update_delete'),
]

Ответ и просьбы ГДРФ

Так же как и Django, Django REST Framework имеет свои собственные специальные Response и Request классы. Они основаны на классах Django HttpRequest и TemplateResponse соответственно, и переработаны для более удобного использования при работе с API и характером данных API.

Django REST Framework Response

Класс DRF Response предоставляет атрибут .data, который аналогичен request.POST, но доступен даже тогда, когда POST не используется метод запроса, и, кроме того, .data обрабатывает произвольные данные, тогда как POST обрабатывает только данные формы, представленные через форму в браузере.

Django REST Framework Request

Класс DRF Response в основном такой же, как и его аналог в Django, за исключением того, что он отображает имеющееся у него содержимое на основе content-type, используемого клиентом. Это означает, что если вы используете браузер, командную строку или программный интерфейс для взаимодействия с API, то получаемый вами ответ будет автоматически соответствовать тому, что лучше для вашего клиента. Возвращаемый content-type будет соответствовать типу содержимого, в котором вы отправили свои данные. Однако вы также можете указать нужный вам ответ content-type, указав расширение конечной точки при вызове, т.е. /endpoint.json

TL;DR: Давайте начнем быстро

Вы пишете приложение для фанатской фантастики о супергероях и хотите, чтобы оно могло переходить с веб-версии на мобильную. Для этого вам нужен API. API нужен уже вчера, так что давайте сделаем это как можно быстрее:

Сначала создайте сериализатор для своей модели. Он служит как для входной проверки, так и для выходной сериализации ответов API:

Использование ModelSerializer для быстрой сериализации существующей модели

Вот наш models.py с определенными моделями и отношениями:

"""
Character models
"""

import random

from django.db import models
from django.urls import reverse_lazy

from .constants import CHARACTER_TYPES, EXTRA


class Character(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()
    profession = models.CharField(max_length=50)  # Choices later
    mentor = models.ForeignKey('Character', models.DO_NOTHING, related_name='proteges', null=True, blank=True)
    team = models.ForeignKey('Team', models.DO_NOTHING, null=True, blank=True)
    type = models.CharField(max_length=20, choices=CHARACTER_TYPES, default=EXTRA)

    def __str__(self):
        return '{name} ({team_name})'.format(name=self.name, team_name=self.team.name)

    @staticmethod
    def get_random_line():
        try:
            return random.choice(Line.objects.all())
        except IndexError:
            return 'Say what..?'

    def get_random_line_modifier(self):
        try:
            return random.choice(self.line_modifiers.all())
        except IndexError:
            return ''

    def get_line(self):
        return '{} {}'.format(self.get_random_line(), self.get_random_line_modifier())

    def get_absolute_url(self):
        return reverse_lazy('characters:detail', kwargs={'pk': self.pk})


class Team(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()

    def __str__(self):
        return self.name


class LineModifier(models.Model):
    character = models.ForeignKey('Character', models.DO_NOTHING, related_name='line_modifiers')
    modifier = models.CharField(max_length=50)

    def __str__(self):
        return self.modifier


class Line(models.Model):

    line_text = models.TextField()

    def __str__(self):
        return self.line_text

А единственный необходимый нам сериализатор мы рассмотрели ранее:

"""
Serializers for Character model
"""

from rest_framework import serializers

from characters.models import Character


class CharacterSerializer(serializers.ModelSerializer):
    mentor = serializers.StringRelatedField()
    team = serializers.StringRelatedField()
    random_line = serializers.SerializerMethodField()

    @staticmethod
    def get_random_line(obj):
        return obj.get_line()

    class Meta:
        model = Character
        fields = (
            'name', 'description', 'profession', 'mentor', 'team', 'type', 'random_line',
        )

Используйте ModelViewSet, чтобы получить представление API за считанные секунды

Для нашего приложения нам пока нужно раскрыть только модель Characters, чтобы ваше приложение с моделью могло CRUD (Create, Retrieve, Update, and Destroy) Characters. Остальные модели будут доступны только для чтения через сериализатор Characters, но мы не будем позволять людям добавлять эти модели через API.

Таким образом, наше использование ModelViewSet выглядит следующим образом:

"""
Views for the Character API
"""
from characters.models import Character
from characters.serializers import CharacterSerializer
from rest_framework import viewsets


class CharacterViewSet(viewsets.ModelViewSet):
    queryset = Character.objects.all()
    serializer_class = CharacterSerializer

Да, именно так. Django REST Framework настолько мощный. Это дает нам действия List, Create, Retrieve, Update (как полное, так и частичное) и Destroy.

Опирайтесь на DefaultRouter для быстрых маршрутов, определяемых на основе ваших ViewSet

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

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

from . import views


router = DefaultRouter()
router.register(r'characters', views.CharacterViewSet)

v3_patterns = [
    path('', include(router.urls)),
]

Благодаря использованию класса DRF DefaultRouter с классом ViewSet, все маршруты создаются автоматически, HTTP-версии обрабатываются соответствующим образом, и даже переключение типов содержимого работает без дополнительной настройки. Из доступного для просмотра API мы можем подтвердить, что json выглядит так, как мы ожидали, GET, PUT, PATCH и DELETE существуют и работают так, как ожидалось. Просто волшебно, как много полезного мы получаем от использования встроенных классов DRF. DRF настолько всеобъемлющ и соответствует спецификации RESTful, что вы знаете, что ваши пользователи получат то, что они ожидают.

Собираем все воедино

Вот как все выглядит после того, как вы соединили части вместе.

У нас есть конечная точка для перечисления и создания символов:

Затем у нас есть конечная точка для просмотра деталей одного персонажа, а также для обновления и удаления этого персонажа:

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

Почти все, что вы здесь видите, было создано с помощью Django REST Framework. Формы, красивое форматирование и навигация - все это просто часть работы DRF. Единственное, что мы сделали, это подключили маршрут и добавили некоторые данные!

Заключение

Фреймворк Django REST Framework является довольно удивительным. API почти всегда требуются в современных приложениях в связи с развитием мобильных устройств. Все, что вы создаете, с первого дня будет получать запросы на создание нативного мобильного приложения.

Теперь, используя DRF, вы можете предоставить API к своим данным и начать создавать мобильное приложение в течение нескольких минут. Все API будут генерироваться на основе существующей модели данных, так что по мере развития ваших моделей будет развиваться и API.

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

DRF также обеспечивает аутентификацию, дросселирование конечных точек, версионирование, пагинацию и кэширование - вот лишь несколько важных элементов, о которых следует помнить при создании веб-приложений.

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

Вернуться на верх