← Назад к вопросам

Зачем нужен Django Rest Framework?

2.3 Middle🔥 201 комментариев
#Django#REST API и HTTP

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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.

Зачем нужен Django Rest Framework? | PrepBro