Основы DRF: сериализаторы и API-представления
Вы уже умеете создавать веб-приложения на Django, которые показывают данные с помощью шаблонов. Но что, если приложению нужно обмениваться данными с другими сервисами, мобильными приложениями или JavaScript-фронтендом? Тут на помощь приходят API (Application Programming Interface), а Django REST Framework (DRF) — мощный инструмент для их создания в Django.
Что такое Django REST Framework (DRF)?
Django REST Framework (DRF) — это набор инструментов для создания веб-API на Django. Он упрощает разработку RESTful API, предлагая готовые решения для:
- сериализации данных
- аутентификации
- авторизации
- маршрутизации
- и многого другого
DRF построен на принципах Django. Если вы знакомы с моделями, представлениями и URL-маршрутизацией Django, освоить DRF будет намного проще.
Сериализаторы: переводчики для данных
В основе DRF лежат сериализаторы. Представьте, что у вас есть данные в базе (например, объект модели Django), и их нужно отправить по сети в формате JSON или XML. Или наоборот: вы получили JSON от клиента и хотите сохранить его в базу. Сериализаторы выполняют эту «переводческую» работу:
- Сериализация: Превращают сложные данные (как экземпляры моделей Django) в простые типы Python, которые легко преобразовать в JSON, XML или другие форматы.
- Десериализация: Превращают простые типы Python (полученные из JSON/XML) обратно в сложные данные, например, для сохранения в базу.
- Валидация: Проверяют входящие данные на соответствие правилам (обязательные поля, типы данных, уникальность).
Создаём сериализатор
Давайте создадим сериализатор для нашей модели Product из интернет-магазина. Вот как она выглядит:
# myapp/models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
in_stock = models.BooleanField(default=True)
def __str__(self):
return self.name
Теперь создадим файл serializers.py в приложении myapp и определим сериализатор:
# myapp/serializers.py
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True) # Только для чтения, генерируется БД
name = serializers.CharField(max_length=100)
description = serializers.CharField(allow_blank=True)
price = serializers.DecimalField(max_digits=10, decimal_places=2)
in_stock = serializers.BooleanField(required=False, default=True)
def create(self, validated_data):
"""
Создаёт и возвращает новый экземпляр `Product`
из проверенных данных.
"""
return Product.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
Обновляет и возвращает существующий экземпляр `Product`
из проверенных данных.
"""
instance.name = validated_data.get('name', instance.name)
instance.description = validated_data.get('description', instance.description)
instance.price = validated_data.get('price', instance.price)
instance.in_stock = validated_data.get('in_stock', instance.in_stock)
instance.save()
return instance
Здесь мы вручную описали каждое поле. Это даёт полный контроль, но для моделей Django есть способ проще — ModelSerializer.
ModelSerializer: быстрый старт
ModelSerializer автоматически создаёт поля сериализатора на основе полей вашей модели Django. Это сильно ускоряет разработку.
# myapp/serializers.py
from rest_framework import serializers
from .models import Product
class ProductModelSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ['id', 'name', 'description', 'price', 'in_stock'] # Поля для сериализации
# Или fields = '__all__' для всех полей модели
# Или exclude = ['some_field'] для исключения полей
Важно:
ModelSerializerсам реализует методыcreate()иupdate(). Очень удобно!
API-представления (API Views)
Как и в обычном Django, DRF использует представления (views) для обработки HTTP-запросов и ответов. Но в DRF представления адаптированы специально для работы с API.
Функциональные API-представления (@api_view)
Для простых случаев используйте декоратор @api_view из DRF. Он превращает обычную функцию представления Django в API-представление, которое может обрабатывать запросы и возвращать ответы DRF.
# myapp/views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Product
from .serializers import ProductModelSerializer
@api_view(['GET', 'POST'])
def product_list(request):
"""
Список всех продуктов или создание нового.
"""
if request.method == 'GET':
products = Product.objects.all()
serializer = ProductModelSerializer(products, many=True) # many=True для списка
return Response(serializer.data)
elif request.method == 'POST':
serializer = ProductModelSerializer(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)
@api_view(['GET', 'PUT', 'DELETE'])
def product_detail(request, pk):
"""
Получение, обновление или удаление одного продукта.
"""
try:
product = Product.objects.get(pk=pk)
except Product.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = ProductModelSerializer(product)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = ProductModelSerializer(product, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
product.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Здесь мы используем Response из rest_framework.response для возврата данных в нужном формате (по умолчанию JSON). request.data автоматически разбирает входящие данные (JSON, формы и т.д.).
Классовые API-представления (Class-based Views)
Для более сложных сценариев и лучшей организации кода DRF предлагает мощные классовые представления. Они позволяют использовать наследование и миксины для создания API-логики.
Базовые классы:
APIView: Основа для всех представлений DRF. Позволяет обрабатывать HTTP-методы (GET, POST и т.д.) как отдельные методы класса.GenericAPIView: РасширяетAPIViewи предоставляет общие методы для работы с queryset'ами и сериализаторами. Очень удобно для типичных операций CRUD (Create, Retrieve, Update, Delete).
Давайте перепишем product_list и product_detail с использованием GenericAPIView и миксинов:
# myapp/views.py
from rest_framework import generics
from .models import Product
from .serializers import ProductModelSerializer
class ProductListCreateAPIView(generics.ListCreateAPIView):
queryset = Product.objects.all()
serializer_class = ProductModelSerializer
class ProductRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Product.objects.all()
serializer_class = ProductModelSerializer
Посмотрите, насколько чище и лаконичнее стал код! Классы ListCreateAPIView и RetrieveUpdateDestroyAPIView (которые наследуются от GenericAPIView и соответствующих миксинов) предоставляют всю логику для списка/создания и получения/обновления/удаления объектов.
Настройка URL-маршрутизации для API
Теперь свяжем наши API-представления с URL-адресами. Это делается так же, как и в обычном Django, через файл urls.py.
# myapp/urls.py
from django.urls import path
from .views import ProductListCreateAPIView, ProductRetrieveUpdateDestroyAPIView
urlpatterns = [
path('products/', ProductListCreateAPIView.as_view(), name='product-list-create'),
path('products/<int:pk>/', ProductRetrieveUpdateDestroyAPIView.as_view(), name='product-retrieve-update-destroy'),
]
Не забудьте включить URL-адреса вашего приложения в главный urls.py проекта:
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('myapp.urls')), # Все API-эндпоинты будут доступны по /api/
]
Теперь запустите сервер Django и перейдите по адресу http://127.0.0.1:8000/api/products/. Вы увидите список продуктов (если они есть) или сможете создать новый, отправив POST-запрос. DRF также предоставляет удобный веб-интерфейс для просмотра и тестирования API прямо в браузере.
Практическое задание
- Создайте новое Django-приложение (или используйте существующее) и добавьте в него простую модель, например,
Bookс полями:title(строка),author(строка),publication_year(целое число). - Создайте
ModelSerializerдля вашей моделиBook. - Реализуйте два классовых API-представления (наследуясь от
generics.ListCreateAPIViewиgenerics.RetrieveUpdateDestroyAPIView) для моделиBook. - Настройте URL-маршрутизацию для этих представлений.
- Запустите сервер и проверьте работу API через браузер или инструмент вроде Postman/Insomnia:
- GET-запрос на
/api/books/(для получения списка книг). - POST-запрос на
/api/books/(для создания новой книги). - GET-запрос на
/api/books/<id>/(для получения конкретной книги). - PUT/PATCH-запрос на
/api/books/<id>/(для обновления книги). - DELETE-запрос на
/api/books/<id>/(для удаления книги).
- GET-запрос на
Поздравляю! Вы сделали первые шаги в создании мощных и гибких API с помощью Django REST Framework. Это открывает огромные возможности для интеграции вашего бэкенда с любыми фронтенд-технологиями и другими сервисами.
В следующем разделе мы углубимся в то, как использовать библиотеку requests для отправки HTTP-запросов к внешним API. Это позволит вашим приложениям взаимодействовать с другими сервисами в интернете.