Уявіть, що у вас є дві моделі в базі даних: User і Profile. Користувач може мати один профіль (зв'язок OneToOne). Якщо ви хочете повернути дані користувача разом із даними його профілю в одному запиті, то вам потрібен вкладений серіалізатор. Він допомагає включити поля пов'язаних моделей у серіалізований результат.
Аналогія: уявіть матрьошку — головна зовнішня лялька містить всередині ще одну ляльку, яка, у свою чергу, може містити іншу. Ось так і працюють вкладені серіалізатори: один серіалізатор може "вкладати" в себе інший.
Практика: створення вкладених серіалізаторів
Давай створимо моделі Author і Book, де кожен автор може написати кілька книг (зв'язок ForeignKey). Наша ціль — повернути дані автора, включаючи список його книг.
from django.db import models
# Модель автора
class Author(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
def __str__(self):
return self.name
# Модель книги
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, related_name='books', on_delete=models.CASCADE)
def __str__(self):
return self.title
Зверни увагу на related_name='books' у полі author. Це спрощує доступ до книг автора через зворотній зв'язок: наприклад, author.books.all().
Створення серіалізаторів
Тепер ми створимо два серіалізатори: один для об'єкта книги BookSerializer, а інший для автора AuthorSerializer, який включає вкладений список книг.
from rest_framework import serializers
from .models import Author, Book
# Серіалізатор для книги
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', 'title']
# Серіалізатор для автора
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer(many=True) # Вкладений серіалізатор
class Meta:
model = Author
fields = ['id', 'name', 'email', 'books']
- Ми створили
BookSerializerдля серіалізації даних про книги. - У
AuthorSerializerми додали полеbooks, яке містить список вкладених об'єктів. Параметрmany=Trueвказує, що поле містить масив даних.
Приклад використання
Для тесту створимо кількох авторів та їхні книги:
from myapp.models import Author, Book
# Створюємо автора
author = Author.objects.create(name="Isaac Asimov", email="asimov@example.com")
# Створюємо книги для автора
Book.objects.create(title="Foundation", author=author)
Book.objects.create(title="I, Robot", author=author)
Тепер скористаємося AuthorSerializer, щоб подивитися, як виглядають дані:
from myapp.serializers import AuthorSerializer
from myapp.models import Author
author = Author.objects.get(name="Isaac Asimov")
serializer = AuthorSerializer(author)
print(serializer.data)
Результат:
{
"id": 1,
"name": "Isaac Asimov",
"email": "asimov@example.com",
"books": [
{
"id": 1,
"title": "Foundation"
},
{
"id": 2,
"title": "I, Robot"
}
]
}
Зміна вкладених даних
Вкладені серіалізатори дозволяють не тільки відображати дані, але й створювати або оновлювати пов'язані об'єкти.
Уявімо, що ти хочеш додати нову книгу через серіалізатор. Для цього потрібно перевизначити метод create().
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer(many=True)
class Meta:
model = Author
fields = ['id', 'name', 'email', 'books']
def create(self, validated_data):
books_data = validated_data.pop('books') # Видаляємо вкладені дані
author = Author.objects.create(**validated_data) # Створюємо автора
for book_data in books_data:
Book.objects.create(author=author, **book_data) # Створюємо книги
return author
Приклад запиту на створення:
{
"name": "George Orwell",
"email": "orwell@example.com",
"books": [
{"title": "1984"},
{"title": "Animal Farm"}
]
}
Результат: новий автор і його книги будуть додані в базу.
Особливості роботи з вкладеними серіалізаторами
Іноді ви можете захотіти зробити вкладені дані тільки для читання. Для цього використовуйте параметр read_only=True:
class AuthorSerializer(serializers.ModelSerializer):
books = BookSerializer(many=True, read_only=True)
class Meta:
model = Author
fields = ['id', 'name', 'email', 'books']
Тепер книги не будуть змінюватися при використанні серіалізатора для створення або оновлення даних.
Продуктивність при роботі з вкладеними серіалізаторами
Якщо ти серіалізуєш велику кількість об'єктів із вкладеними даними, це може призвести до численних запитів до бази даних. Щоб уникнути цього, використовуй select_related() і prefetch_related():
authors = Author.objects.prefetch_related('books').all()
serializer = AuthorSerializer(authors, many=True)
Це значно зменшить кількість запитів, які робить твій додаток, і пришвидшить роботу.
Помилка: "Got a TypeError: Object of type 'Book' is not JSON serializable".
Якщо ти забув, що Serializer потрібен для перетворення моделей у серіалізовані формати, ти можеш зіткнутися з подібною помилкою. Переконайся, що всі вкладені об'єкти обробляються через серіалізатори.
Рекомендації для роботи
Коли використовувати вкладені серіалізатори? Є кілька основних кейсів:
- Прості залежності: коли потрібно показати пов'язані дані простим списком або об'єктом.
- Читання даних: коли вам потрібно показати пов'язані дані клієнту.
- Невеликі обсяги даних: вкладені серіалізатори підходять для обробки невеликих обсягів даних. Для більш складних сценаріїв може знадобитися розділення запитів.
У реальній роботі:
- Використовуйте вкладені серіалізатори для читання даних, але уникайте складної логіки створення/оновлення без необхідності.
- Основні сценарії оновлень краще обробляти на рівні представлень (views).
- Оптимізуйте запити за допомогою
select_related()таprefetch_related()для мінімізації навантаження на базу даних.
Тепер, коли ви знаєте, як використовувати вкладені серіалізатори, давайте додамо їх у наш проєкт і почнемо експериментувати.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ