Зачем нужен Django Rest Framework?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Django Rest Framework (DRF)
Django Rest Framework — это мощный инструмент для разработки REST API на Python. Он предоставляет готовые компоненты для построения профессиональных веб-сервисов.
Основные проблемы без DRF
Django без DRF (много кода, нужно писать все вручную)
from django.http import JsonResponse
from django.views import View
import json
# Нужно вручную парсить JSON
class UsersView(View):
def get(self, request):
users = User.objects.all()
data = []
for user in users:
data.append({
'id': user.id,
'name': user.name,
'email': user.email,
})
return JsonResponse(data, safe=False)
def post(self, request):
# Парсируем JSON вручную
body = json.loads(request.body)
# Валидируем вручную
if not body.get('name'):
return JsonResponse({'error': 'Name required'}, status=400)
if not body.get('email'):
return JsonResponse({'error': 'Email required'}, status=400)
# Создаем пользователя
user = User.objects.create(
name=body['name'],
email=body['email']
)
return JsonResponse({
'id': user.id,
'name': user.name,
'email': user.email,
})
# Проблемы:
# - Много кода для простой задачи
# - Нет валидации по умолчанию
# - Нет пагинации
# - Нет фильтрации
# - Нет сортировки
Решение: Django Rest Framework
С DRF (минимум кода, много функционала)
from rest_framework import serializers, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
# 1. Сериализатор — описываем структуру данных
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'name', 'email', 'created_at']
read_only_fields = ['id', 'created_at']
# Валидация встроена автоматически
# 2. ViewSet — получаем CRUD операции автоматически
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
filterset_fields = ['name', 'email'] # Фильтрация
ordering_fields = ['created_at', 'name'] # Сортировка
pagination_class = DefaultPagination # Пагинация
# Кастомный action
@action(detail=True, methods=['post'])
def send_email(self, request, pk=None):
user = self.get_object()
# Отправляем email
return Response({'status': 'email sent'})
# 3. Регистрируем в urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]
# Результат: автоматически получаем:
# GET /api/users/ — список
# GET /api/users/123/ — детали
# POST /api/users/ — создание
# PUT /api/users/123/ — обновление
# DELETE /api/users/123/ — удаление
# POST /api/users/123/send_email/ — кастомный action
Основные компоненты DRF
1. Serializers — валидация и трансформация данных
from rest_framework import serializers
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
# Кастомное поле
full_email = serializers.SerializerMethodField()
class Meta:
model = User
fields = ['id', 'username', 'email', 'full_email']
def get_full_email(self, obj):
return f'{obj.username} <{obj.email}>'
# Валидация одного поля
def validate_email(self, value):
if User.objects.filter(email=value).exists():
raise serializers.ValidationError('Email already exists')
return value
# Валидация нескольких полей
def validate(self, data):
if data['username'] == data['email'].split('@')[0]:
raise serializers.ValidationError('Username cannot be same as email')
return data
# Использование
serializer = UserSerializer(user)
print(serializer.data) # {'id': 1, 'username': 'alice', 'email': ...}
# Валидация при создании
data = {'username': 'bob', 'email': 'bob@example.com'}
serializer = UserSerializer(data=data)
if serializer.is_valid():
user = serializer.save()
else:
print(serializer.errors) # {'email': ['Email already exists']}
2. ViewSets — CRUD операции из коробки
from rest_framework.viewsets import ViewSet, ModelViewSet, ReadOnlyModelViewSet
from rest_framework.response import Response
from rest_framework.decorators import action
# Базовый ViewSet
class ProductViewSet(ViewSet):
def list(self, request):
products = Product.objects.all()
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
product = Product.objects.get(pk=pk)
serializer = ProductSerializer(product)
return Response(serializer.data)
# ModelViewSet — автоматический CRUD
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
# Автоматически: list, retrieve, create, update, destroy
# ReadOnlyModelViewSet — только чтение
class ProductViewSet(ReadOnlyModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
# Только: list, retrieve
# Кастомные actions
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
@action(detail=False, methods=['get'])
def bestsellers(self, request):
products = Product.objects.filter(sales__gt=1000)
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)
@action(detail=True, methods=['post'])
def add_review(self, request, pk=None):
product = self.get_object()
Review.objects.create(
product=product,
rating=request.data['rating'],
text=request.data['text']
)
return Response({'status': 'review added'})
3. Permissions и Authentication
from rest_framework import permissions
from rest_framework.decorators import permission_classes
class IsOwner(permissions.BasePermission):
"""Только владелец может редактировать"""
def has_object_permission(self, request, view, obj):
return obj.owner == request.user
class PostViewSet(ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = [permissions.IsAuthenticated, IsOwner]
def perform_create(self, serializer):
# Устанавливаем текущего пользователя как автора
serializer.save(author=self.request.user)
# Встроенные permissions
# permissions.IsAuthenticated — только авторизованные
# permissions.IsAdminUser — только админы
# permissions.AllowAny — все
# permissions.DjangoModelPermissions — права Django
4. Пагинация, фильтрация, поиск
from rest_framework.pagination import PageNumberPagination
from rest_framework.filters import SearchFilter, OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
class CustomPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
pagination_class = CustomPagination
# Фильтрация
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['category', 'price']
search_fields = ['name', 'description'] # Полнотекстный поиск
ordering_fields = ['price', 'created_at'] # Сортировка
ordering = ['-created_at'] # По умолчанию новые первыми
# Использование:
# GET /products/?page=1&page_size=10
# GET /products/?category=electronics&price__gte=100
# GET /products/?search=laptop
# GET /products/?ordering=-price
Практический пример: API блога
from rest_framework import serializers, viewsets, filters, status
from rest_framework.response import Response
from rest_framework.decorators import action
from rest_framework.pagination import PageNumberPagination
# Модели
class Blog(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class Comment(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(User, on_delete=models.CASCADE)
text = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
# Сериализаторы
class CommentSerializer(serializers.ModelSerializer):
author_name = serializers.CharField(source='author.username', read_only=True)
class Meta:
model = Comment
fields = ['id', 'text', 'author_name', 'created_at']
class BlogSerializer(serializers.ModelSerializer):
comments = CommentSerializer(many=True, read_only=True)
author_name = serializers.CharField(source='author.username', read_only=True)
class Meta:
model = Blog
fields = ['id', 'title', 'content', 'author_name', 'comments', 'created_at']
# ViewSets
class BlogViewSet(viewsets.ModelViewSet):
queryset = Blog.objects.all()
serializer_class = BlogSerializer
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = ['title', 'content']
ordering_fields = ['created_at']
pagination_class = PageNumberPagination
def perform_create(self, serializer):
serializer.save(author=self.request.user)
@action(detail=True, methods=['post'])
def add_comment(self, request, pk=None):
blog = self.get_object()
serializer = CommentSerializer(data=request.data)
if serializer.is_valid():
serializer.save(blog=blog, author=request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# URLs
router = DefaultRouter()
router.register(r'blogs', BlogViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]
Преимущества DRF
✓ Минимум кода — автоматический CRUD ✓ Валидация — встроенная в сериализаторы ✓ Пагинация — из коробки ✓ Фильтрация и поиск — готовые фильтры ✓ Аутентификация — встроенная поддержка ✓ Разрешения — легко настраивается ✓ Тестирование — встроенные тестовые клиенты ✓ API документация — автоматическая Swagger/OpenAPI ✓ Обработка ошибок — стандартные коды ошибок ✓ Content negotiation — поддержка JSON, XML, и др.
Когда использовать DRF
✓ REST API для Django проекта ✓ Быстрая разработка ✓ Стандартные CRUD операции ✓ Нужна документация API ✓ Многоэкранные приложения
Когда использовать FastAPI вместо DRF
✓ Асинхронный код (async/await) ✓ Высокая производительность ✓ Микросервисы ✓ Новый проект без Django ✓ Высокая пропускная способность
Вывод
Django Rest Framework — это стандарт для REST API на Django. Он экономит часы разработки, обеспечивает качество и лучшие практики. Любой Django API проект должен использовать DRF.