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

В каком случае вызывается update в сериализаторе (serializer)

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

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

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

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

# Метод update() в Django REST Framework сериализаторе

Метод update() в сериализаторе вызывается в одном конкретном случае: когда нужно обновить существующий объект в БД. Сейчас подробнее разберу, когда и как это происходит.

Основной принцип

Есть два основных метода для создания/обновления объектов:

  • create() — создаёт новый объект
  • update() — изменяет существующий объект

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

Когда вызывается update()

Случай 1: Сериализатор инициализирован с instance

Если при создании сериализатора передаём существующий объект:

from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ['id', 'title', 'content', 'created_at']
    
    def update(self, instance, validated_data):
        """Вызывается при обновлении существующей статьи"""
        instance.title = validated_data.get('title', instance.title)
        instance.content = validated_data.get('content', instance.content)
        instance.save()
        return instance

# В представлении
from rest_framework.response import Response
from rest_framework.views import APIView

class ArticleUpdateView(APIView):
    def put(self, request, pk):
        article = Article.objects.get(pk=pk)  # получаем существующий объект
        
        # ЗДЕСЬ ВЫЗЫВАЕТСЯ update(), потому что передаём instance
        serializer = ArticleSerializer(article, data=request.data)
        
        if serializer.is_valid():
            serializer.save()  # вызывает update(instance, validated_data)
            return Response(serializer.data)
        return Response(serializer.errors, status=400)

Случай 2: Обновление через ViewSet

from rest_framework import viewsets

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    
    # При PUT запросе на /articles/1/ автоматически:
    # 1. Получает объект Article с pk=1
    # 2. Инициализирует сериализатор с instance=article
    # 3. Вызывает update() при save()

Сравнение: create vs update

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ['id', 'title', 'content']
    
    def create(self, validated_data):
        """Вызывается при создании НОВОГО объекта"""
        print("CREATE вызывается")
        return Article.objects.create(**validated_data)
    
    def update(self, instance, validated_data):
        """Вызывается при обновлении СУЩЕСТВУЮЩЕГО объекта"""
        print("UPDATE вызывается")
        instance.title = validated_data.get('title', instance.title)
        instance.save()
        return instance

# СОЗДАНИЕ (create)
data = {'title': 'New Article', 'content': 'Text'}
serializer = ArticleSerializer(data=data)  # БЕЗ instance
if serializer.is_valid():
    serializer.save()  # вызывает create()
    # OUTPUT: "CREATE вызывается"

# ОБНОВЛЕНИЕ (update)
article = Article.objects.first()
data = {'title': 'Updated Title', 'content': 'New Text'}
serializer = ArticleSerializer(article, data=data)  # С instance
if serializer.is_valid():
    serializer.save()  # вызывает update()
    # OUTPUT: "UPDATE вызывается"

Как Django REST Framework решает, какой метод вызвать

# В базовом классе Serializer
class Serializer:
    def save(self, **kwargs):
        """
        Сохранение или обновление объекта на основе наличия instance
        """
        if self.instance is not None:
            # Объект был передан при инициализации → ОБНОВЛЕНИЕ
            self.instance = self.update(self.instance, self.validated_data)
        else:
            # Объект не передан → СОЗДАНИЕ
            self.instance = self.create(self.validated_data)
        
        return self.instance

Практический пример: обновление с custom логикой

from rest_framework import serializers
from .models import User, Profile

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'email']
    
    def update(self, instance, validated_data):
        # Можем добавить custom логику
        email_changed = validated_data.get('email') != instance.email
        
        # Обновляем поля
        instance.username = validated_data.get('username', instance.username)
        instance.email = validated_data.get('email', instance.email)
        instance.save()
        
        # Если email изменился, отправляем подтверждение
        if email_changed:
            send_email_verification(instance.email)
        
        return instance

Обновление с вложенными объектами

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = ['id', 'text', 'author']

class ArticleSerializer(serializers.ModelSerializer):
    comments = CommentSerializer(many=True, read_only=False)
    
    class Meta:
        model = Article
        fields = ['id', 'title', 'comments']
    
    def update(self, instance, validated_data):
        comments_data = validated_data.pop('comments', [])
        
        # Обновляем саму статью
        instance.title = validated_data.get('title', instance.title)
        instance.save()
        
        # Обновляем связанные комментарии
        for comment_data in comments_data:
            comment_id = comment_data.get('id')
            if comment_id:
                comment = Comment.objects.get(id=comment_id)
                comment.text = comment_data.get('text', comment.text)
                comment.save()
        
        return instance

Важные моменты

1. Разница между PUT и PATCH

# PUT — обновление всех полей (полная замена)
# instance передаётся → вызывается update()
data = {'title': 'New Title', 'content': 'New Content'}
serializer = ArticleSerializer(article, data=data, partial=False)

# PATCH — обновление только переданных полей
# instance передаётся → вызывается update()
data = {'title': 'New Title'}  # content не меняется
serializer = ArticleSerializer(article, data=data, partial=True)

2. Частичное обновление

def update(self, instance, validated_data):
    # partial=True позволяет обновлять только переданные поля
    for attr, value in validated_data.items():
        setattr(instance, attr, value)
    instance.save()
    return instance

3. Обновление с доступом к request

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ['id', 'title', 'content']
    
    def update(self, instance, validated_data):
        # Можем получить доступ к request
        request = self.context.get('request')
        user = request.user if request else None
        
        # Логируем, кто обновил
        instance.updated_by = user
        instance.title = validated_data.get('title', instance.title)
        instance.save()
        
        return instance

Резюме: когда вызывается update()

context: нет instance
serializer = Serializer(data=data)  → save() вызовет create()

context: есть instance
serializer = Serializer(instance, data=data)  → save() вызовет update()

В ViewSet:
POST /articles/  → create()
GET /articles/1/  → retrieve() (ничего не сохраняется)
PUT /articles/1/  → update()
PATCH /articles/1/  → partial_update()
DELETE /articles/1/  → destroy()

Метод update() вызывается только когда обновляем существующий объект, в отличие от create(), который создаёт новый.

В каком случае вызывается update в сериализаторе (serializer) | PrepBro