✅ Решения практикума 7

⚡ Все решения — итог

# Задачи 1, 2, 5 — базовые CRUD
class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = '__all__'

# Задачи 3.1, 4.1, 6.1, 7.1, 8.1 — read с nested
class ProductSerializer(serializers.ModelSerializer):
    category = CategorySerializer(read_only=True)
    supplier = SupplierSerializer(read_only=True)
    class Meta:
        model = Product
        fields = '__all__'

# Задачи 3.2, 4.2, 7.2, 8.2 — write с FK
class ProductCreateUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'

# Задача 6.1 — read_only_fields
class CustomerSerializer(serializers.ModelSerializer):
    address = AddressSerializer(read_only=True)
    class Meta:
        model = Customer
        fields = '__all__'
        read_only_fields = ['date_joined', 'deleted', 'deleted_at']

# Задача 6.3 — валидация телефона
def validate_phone_number(self, value):
    if not re.match(r'^\d{10,15}$', value):
        raise serializers.ValidationError('...')
    return value

# Задача 8.3 — валидация quantity
def validate_quantity(self, value):
    if value > 1000:
        raise serializers.ValidationError('...')
    return value

Задача 1 — CategorySerializer

Разбор: Минимальный ModelSerializer. fields = '__all__' включает все поля модели автоматически. Подходит для всех CRUD-операций.

from rest_framework import serializers
from .models import Category

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = '__all__'

Что происходит: DRF читает определение модели Category и создаёт соответствующие поля сериализатора. id — только для чтения автоматически (primary key).

Задача 2 — SupplierSerializer

Разбор: Аналогично Category — базовый CRUD-сериализатор для поставщика.

from rest_framework import serializers
from .models import Supplier

class SupplierSerializer(serializers.ModelSerializer):
    class Meta:
        model = Supplier
        fields = '__all__'

Задача 3.1 — ProductSerializer (чтение)

Разбор: Для GET-запросов нужны полные данные связанных объектов. Переопределяем поля category и supplier вложенными сериализаторами с read_only=True.

from rest_framework import serializers
from .models import Product, Category, Supplier

class ProductSerializer(serializers.ModelSerializer):
    category = CategorySerializer(read_only=True)
    supplier = SupplierSerializer(read_only=True)

    class Meta:
        model = Product
        fields = '__all__'

Ключевое: read_only=True говорит DRF «не принимай этот объект при POST/PUT, только выводи». Без этого флага DRF попытается валидировать вложенный объект при создании.

Задача 3.2 — ProductCreateUpdateSerializer (запись)

Разбор: Для POST/PUT принимаем числовые ID (FK), не вложенные объекты. Достаточно не переопределять поля — DRF сам создаст PrimaryKeyRelatedField.

from rest_framework import serializers
from .models import Product

class ProductCreateUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'

Пример запроса: POST /api/products/ {"name": "Молоко", "category": 3, "supplier": 1, "price": "89.99"}

Задача 4.1 — ProductDetailSerializer (чтение)

Разбор: ProductDetail связан с Product через OneToOne или FK. При чтении показываем полный объект Product.

from rest_framework import serializers
from .models import ProductDetail, Product

class ProductDetailSerializer(serializers.ModelSerializer):
    product = ProductSerializer(read_only=True)

    class Meta:
        model = ProductDetail
        fields = '__all__'

Задача 4.2 — ProductDetailCreateUpdateSerializer (запись)

from rest_framework import serializers
from .models import ProductDetail

class ProductDetailCreateUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProductDetail
        fields = '__all__'

Задача 5 — AddressSerializer

from rest_framework import serializers
from .models import Address

class AddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = Address
        fields = '__all__'

Задача 6.1 — CustomerSerializer (чтение)

Разбор: Два требования: вложенный Address + поля date_joined, deleted, deleted_at только для чтения.

from rest_framework import serializers
from .models import Customer, Address

class CustomerSerializer(serializers.ModelSerializer):
    address = AddressSerializer(read_only=True)

    class Meta:
        model = Customer
        fields = '__all__'
        read_only_fields = ['date_joined', 'deleted', 'deleted_at']

Пояснение read_only_fields: Поля включены в вывод, но при POST/PUT клиент не может их изменить — они будут проигнорированы.

Задача 6.2 — CustomerCreateUpdateSerializer (запись)

Разбор: Явно перечисляем только нужные поля. Служебные поля (date_joined, deleted, deleted_at) просто отсутствуют в fields — они не принимаются и не выводятся.

from rest_framework import serializers
from .models import Customer

class CustomerCreateUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Customer
        fields = ['first_name', 'last_name', 'email', 'phone_number', 'address']

Задача 6.3 — Валидация phone_number

Разбор: Добавляем метод validate_phone_number в CustomerCreateUpdateSerializer. Регулярное выражение ^\d{10,15}$ — только цифры, 10–15 символов.

from rest_framework import serializers
from .models import Customer
import re

class CustomerCreateUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Customer
        fields = ['first_name', 'last_name', 'email', 'phone_number', 'address']

    def validate_phone_number(self, value):
        if not re.match(r'^\d{10,15}$', value):
            raise serializers.ValidationError(
                'Номер телефона должен содержать от 10 до 15 цифр.'
            )
        return value

Проверка: Корректно: "79991234567" (11 цифр). Некорректно: "+7 999 123-45-67" (содержит нецифровые символы).

Задача 7.1 — OrderSerializer (чтение)

from rest_framework import serializers
from .models import Order, Customer

class OrderSerializer(serializers.ModelSerializer):
    customer = CustomerSerializer(read_only=True)

    class Meta:
        model = Order
        fields = '__all__'
        read_only_fields = ['order_date']

Почему order_date read_only: Это поле обычно устанавливается как auto_now_add=True — дата создания заказа выставляется автоматически и не должна меняться.

Задача 7.2 — OrderCreateUpdateSerializer (запись)

from rest_framework import serializers
from .models import Order

class OrderCreateUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Order
        fields = '__all__'
        read_only_fields = ['order_date']

Примечание: Здесь read_only_fields тоже нужен — даже в write-сериализаторе order_date не должна приниматься от клиента.

Задача 8.1 — OrderItemSerializer (чтение)

Разбор: Самый сложный read-сериализатор — два вложенных объекта, каждый со своей вложенностью.

from rest_framework import serializers
from .models import OrderItem, Product, Order

class OrderItemSerializer(serializers.ModelSerializer):
    product = ProductSerializer(read_only=True)
    order = OrderSerializer(read_only=True)

    class Meta:
        model = OrderItem
        fields = '__all__'

Задача 8.2 — OrderItemCreateUpdateSerializer (запись)

from rest_framework import serializers
from .models import OrderItem

class OrderItemCreateUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderItem
        fields = '__all__'

Задача 8.3 — Валидация quantity

from rest_framework import serializers
from .models import OrderItem

class OrderItemCreateUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderItem
        fields = '__all__'

    def validate_quantity(self, value):
        if value > 1000:
            raise serializers.ValidationError(
                'Количество товара должно быть не больше тысячи.'
            )
        return value

Проверка: Корректно: quantity=500. Некорректно: quantity=1001 — вернёт 400 Bad Request.

← К оглавлению урока    ← Задания    Ошибки →