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

Как мы получаем модель, если сериализатор (serializer) уже заполнен?

2.0 Middle🔥 171 комментариев
#Soft Skills

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

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

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

Как мы получаем модель, если сериализатор (serializer) уже заполнен

Это вопрос о паттерне работы с сериализаторами в Django REST Framework (DRF) и как преобразовать валидированные данные в модель объекта.

Базовый поток: Data → Serializer → Model

Обычный процесс выглядит так:

from rest_framework import serializers
from myapp.models import User

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'email']

# 1. Получаем JSON данные
data = {'username': 'john', 'email': 'john@example.com'}

# 2. Передаём в сериализатор
serializer = UserSerializer(data=data)

# 3. Валидируем
if serializer.is_valid():
    # 4. Получаем модель — вот тут несколько вариантов
    user = serializer.save()  # Сохраняет в БД и возвращает User объект

Способ 1: .save() — сохранить и получить модель

Это самый простой способ — валидированные данные сразу сохраняются в БД:

serializer = UserSerializer(data=request.data)
if serializer.is_valid():
    user = serializer.save()  # Возвращает User объект
    return Response({'id': user.id})

Как это работает под капотом:

class ModelSerializer(Serializer):
    def save(self, **kwargs):
        validated_data = {**self.validated_data, **kwargs}
        
        if self.instance is None:
            # Create mode — новый объект
            self.instance = self.Meta.model.objects.create(**validated_data)
        else:
            # Update mode — обновляем существующий
            for attr, value in validated_data.items():
                setattr(self.instance, attr, value)
            self.instance.save()
        
        return self.instance

Способ 2: .validated_data — получить очищенные данные без сохранения

Иногда нужны данные БЕЗ сохранения в БД:

serializer = UserSerializer(data=request.data)
if serializer.is_valid():
    # Получаем очищенные данные
    validated_data = serializer.validated_data
    print(validated_data)  # OrderedDict([('username', 'john'), ('email', 'john@example.com')])
    
    # Создаём модель БЕЗ сохранения
    user = User(**validated_data)  # commit=False эффект
    # Можно делать дополнительные операции
    user.is_active = True
    user.save()  # Сохраняем сам

Способ 3: Кастомный create() метод

Когда логика создания сложнее:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email', 'password']
    
    def create(self, validated_data):
        # Кастомная логика создания
        password = validated_data.pop('password')
        user = User(**validated_data)
        user.set_password(password)  # Хэшируем пароль
        user.save()
        return user

# Использование:
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
    user = serializer.save()  # Вызывает create()

Способ 4: Кастомный update() метод

Для обновления существующей модели:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email']
    
    def update(self, instance, validated_data):
        # instance — существующий User
        instance.username = validated_data.get('username', instance.username)
        instance.email = validated_data.get('email', instance.email)
        instance.save()
        return instance

# Использование:
user = User.objects.get(id=1)
serializer = UserSerializer(user, data=request.data, partial=True)
if serializer.is_valid():
    updated_user = serializer.save()  # Вызывает update()

Способ 5: Instance mode (Partial update)

Когда нужно обновить конкретный объект (partial update):

# PATCH запрос — обновляем только переданные поля
user = User.objects.get(id=1)
serializer = UserSerializer(
    user,
    data={'email': 'newemail@example.com'},
    partial=True  # Не требует все поля!
)

if serializer.is_valid():
    updated_user = serializer.save()
    return Response(UserSerializer(updated_user).data)

Способ 6: Получение модели из вложенного сериализатора

Когда есть nested relationships:

class AddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = Address
        fields = ['city', 'country']

class UserSerializer(serializers.ModelSerializer):
    address = AddressSerializer()
    
    class Meta:
        model = User
        fields = ['username', 'address']
    
    def create(self, validated_data):
        address_data = validated_data.pop('address')
        # Создаём Address первым
        address = Address.objects.create(**address_data)
        # Потом User
        user = User.objects.create(address=address, **validated_data)
        return user

# Использование:
data = {
    'username': 'john',
    'address': {'city': 'Moscow', 'country': 'Russia'}
}
serializer = UserSerializer(data=data)
if serializer.is_valid():
    user = serializer.save()  # Возвращает User с nested Address

Способ 7: Получить модель и дополнительные данные

Вернуть модель + дополнительный контекст:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email']
    
    def create(self, validated_data):
        user = User.objects.create(**validated_data)
        return user

# В view:
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
    user = serializer.save()
    return Response({
        'user': UserSerializer(user).data,
        'message': 'User created successfully',
        'id': user.id
    })

Способ 8: Работа с to_representation()

Когда нужна специальная сериализация после сохранения:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email']
    
    def to_representation(self, instance):
        # После создания модели — специальное отображение
        data = super().to_representation(instance)
        data['full_name'] = f"{instance.first_name} {instance.last_name}"
        return data

# Использование:
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
    user = serializer.save()
    # to_representation() вызывается автоматически в return
    return Response(serializer.data)

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

1. .is_valid() обязателен:

# Плохо — использование без валидации
user = User(**serializer.data)

# Хорошо
if serializer.is_valid():
    user = serializer.save()

2. Разница между .data и .validated_data:

# .validated_data — очищенные входные данные (не сохранённые)
validated_data = serializer.validated_data

# .data — сериализованный output (результат to_representation)
response_data = serializer.data

3. Instance vs Data:

# Создание (нет instance)
serializer = UserSerializer(data=request.data)

# Обновление (есть instance)
user = User.objects.get(id=1)
serializer = UserSerializer(user, data=request.data)

4. Вариант с transaction для атомарности:

from django.db import transaction

serializer = UserSerializer(data=request.data)
if serializer.is_valid():
    with transaction.atomic():
        user = serializer.save()
        # Другие операции
    return Response(serializer.data)