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

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

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

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

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

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

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

Метод create() в сериализаторе — это один из ключевых методов для создания объектов из валидированных данных. Давайте разберёмся, когда и как он вызывается.

Жизненный цикл сериализатора

Прежде всего, нужно понять процесс:

1. Получить данные (JSON от клиента)
   ↓
2. Валидировать данные (is_valid())
   ↓
3. Если валиден → вызвать create() или update()
   ↓
4. Вернуть результат

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

Метод create() вызывается только в следующих случаях:

  1. Вы явно вызваете .save() на новом сериализаторе (без instance)
  2. Вы используете это в ViewSet с методом POST
  3. Вы обновляете данные через сериализатор с вызовом .save()

Случай 1: Явный вызов save() при создании

from rest_framework import serializers
from django.contrib.auth.models import User

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'email']
    
    def create(self, validated_data):
        print("create() вызван!")  # ← Это будет выведено
        # Здесь создаём объект
        return User.objects.create(**validated_data)

# В вашем view или тесте
data = {'username': 'alice', 'email': 'alice@example.com'}
serializer = UserSerializer(data=data)  # ← Важно: data= параметр

if serializer.is_valid():
    user = serializer.save()  # ← Здесь вызывается create()
    print(user)  # <User: alice>

Ключевой момент: когда передаём data= параметр (без instance=), это признак создания нового объекта.

Случай 2: ModelViewSet с POST

from rest_framework import viewsets
from rest_framework.decorators import api_view
from rest_framework.response import Response
from django.contrib.auth.models import User

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    
    # ViewSet автоматически обрабатывает POST:
    # POST /api/users/ → create() вызывается

# Фактически ViewSet это делает:
# if request.method == 'POST':
#     serializer = self.serializer_class(data=request.data)
#     if serializer.is_valid():
#         serializer.save()  # ← create() вызывается здесь

Случай 3: Частый баг — update() вместо create()

# НЕПРАВИЛЬНО: это вызовет update(), не create()
user = User.objects.get(id=1)
data = {'username': 'bob'}
serializer = UserSerializer(user, data=data)  # ← instance= передан!

if serializer.is_valid():
    serializer.save()  # ← Вызывает update(), НЕ create()!

Полный пример: когда вызывается create() vs update()

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'first_name']
    
    def create(self, validated_data):
        print(f"CREATE: {validated_data}")
        return User.objects.create(**validated_data)
    
    def update(self, instance, validated_data):
        print(f"UPDATE: {instance} with {validated_data}")
        for key, value in validated_data.items():
            setattr(instance, key, value)
        instance.save()
        return instance

# Сценарий 1: Создание нового пользователя
data = {'username': 'alice', 'email': 'alice@example.com', 'first_name': 'Alice'}
serializer = UserSerializer(data=data)
if serializer.is_valid():
    serializer.save()
# Вывод: CREATE: {'username': 'alice', ...}

# Сценарий 2: Обновление существующего пользователя
existing_user = User.objects.get(username='alice')
data = {'first_name': 'Alicia'}  # Изменяем только first_name
serializer = UserSerializer(existing_user, data=data, partial=True)
if serializer.is_valid():
    serializer.save()
# Вывод: UPDATE: <User: alice> with {'first_name': 'Alicia'}

Разница между instance и data параметрами

# 1. Только data= → CREATE
serializer = UserSerializer(data={'username': 'bob'})
if serializer.is_valid():
    serializer.save()  # create() вызвана

# 2. instance= и data= → UPDATE
user = User.objects.get(id=1)
serializer = UserSerializer(instance=user, data={'username': 'bob'})
if serializer.is_valid():
    serializer.save()  # update() вызвана

# 3. Только instance= → Нет вызова (просто сериализуем объект для вывода)
user = User.objects.get(id=1)
serializer = UserSerializer(instance=user)  # Только чтение
print(serializer.data)  # {'id': 1, 'username': 'bob', ...}

Пользовательская логика в create()

Часто в create() нужна дополнительная логика:

Пример 1: Создание связанных объектов

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ['id', 'title', 'content', 'author_id']
    
    def create(self, validated_data):
        # Добавляем текущего пользователя как автора
        validated_data['author'] = self.context['request'].user
        return Post.objects.create(**validated_data)

# В view:
class PostViewSet(viewsets.ModelViewSet):
    serializer_class = PostSerializer
    
    def get_serializer_context(self):
        context = super().get_serializer_context()
        # Передаём request в контекст сериализатора
        return context

Пример 2: Хеширование пароля

class UserCreateSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)
    
    class Meta:
        model = User
        fields = ['username', 'email', 'password']
    
    def create(self, validated_data):
        password = validated_data.pop('password')  # Извлекаем пароль
        user = User.objects.create(**validated_data)
        user.set_password(password)  # Хешируем пароль
        user.save()
        return user

# Использование
data = {'username': 'alice', 'email': 'alice@example.com', 'password': 'secret123'}
serializer = UserCreateSerializer(data=data)
if serializer.is_valid():
    user = serializer.save()  # create() хеширует пароль

Пример 3: Создание нескольких связанных объектов

class OrderItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderItem
        fields = ['product_id', 'quantity']

class OrderSerializer(serializers.ModelSerializer):
    items = OrderItemSerializer(many=True)  # Вложенные данные
    
    class Meta:
        model = Order
        fields = ['id', 'user_id', 'items']
    
    def create(self, validated_data):
        items_data = validated_data.pop('items')
        
        # Создаём заказ
        order = Order.objects.create(**validated_data)
        
        # Создаём позиции в заказе
        for item_data in items_data:
            OrderItem.objects.create(order=order, **item_data)
        
        return order

# Использование
data = {
    'user_id': 1,
    'items': [
        {'product_id': 5, 'quantity': 2},
        {'product_id': 7, 'quantity': 1}
    ]
}
serializer = OrderSerializer(data=data)
if serializer.is_valid():
    order = serializer.save()  # create() создаёт заказ и позиции

Сравнение: явный create() vs автоматический

# 1. Автоматический create() (ModelSerializer)
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email']
    # create() и update() уже реализованы, не переопределяем

# 2. Пользовательский create() (для дополнительной логики)
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email']
    
    def create(self, validated_data):
        # Добавляем логику до создания
        validated_data['email_verified'] = False
        user = User.objects.create(**validated_data)
        # Отправляем email подтверждения
        send_verification_email(user)
        return user

# 3. Сериализатор без модели (Serializer)
class ContactSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=100)
    email = serializers.EmailField()
    message = serializers.CharField(max_length=1000)
    
    def create(self, validated_data):
        # Нет модели, нужно реализовать вручную
        # Например, отправить email
        send_contact_email(
            to=validated_data['email'],
            subject=f"Message from {validated_data['name']}",
            body=validated_data['message']
        )
        # Или сохранить в БД вручную
        Contact.objects.create(**validated_data)
        return validated_data

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

1. Контекст в create()

def create(self, validated_data):
    # Вы можете получить доступ к request
    user = self.context['request'].user
    print(user)  # Текущий пользователь
    
    # Используйте это для привязки к текущему пользователю
    validated_data['created_by'] = user
    return Post.objects.create(**validated_data)

2. Исключения в create()

def create(self, validated_data):
    try:
        return User.objects.create(**validated_data)
    except IntegrityError:
        raise serializers.ValidationError({
            'username': 'Пользователь с таким именем уже существует'
        })

3. Atomicity: все или ничего

from django.db import transaction

def create(self, validated_data):
    with transaction.atomic():  # Если ошибка — откатываем всё
        order = Order.objects.create(**validated_data)
        for item_data in validated_data['items']:
            OrderItem.objects.create(order=order, **item_data)
        return order

Проверка: как понять, вызовется ли create()

# Проверка 1: есть ли data параметр?
serializer = UserSerializer(data=request.data)  # ← ДА → create()
serializer = UserSerializer(instance=user)      # ← НЕТ → нет create()

# Проверка 2: есть ли instance параметр?
serializer = UserSerializer(data=request.data)        # ← instance НЕТ → create()
serializer = UserSerializer(user, data=request.data)  # ← instance ЕСТЬ → update()

# Проверка 3: вызывается ли save()?
serializer.is_valid()  # Просто валидируем
serializer.save()      # ← Это вызывает create() или update()

Заключение

create() в сериализаторе вызывается когда:

✅ Вы передали только data= параметр (без instance=) ✅ Вы вызвали .save() на сериализаторе ✅ Обычно в POST запросах (создание новых объектов)

Это место для:

  • Дополнительной валидации
  • Специальной логики при создании
  • Создания связанных объектов
  • Отправки уведомлений
  • Логирования событий