✅ Решения практикума 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.