Ответ
Для обработки полей ManyToManyField в сериализаторах Django REST Framework (DRF) существует несколько подходов, выбор которых зависит от желаемого представления данных (ID, строковое представление или вложенный объект).
Основные подходы:
-
PrimaryKeyRelatedField(по ID) Наиболее простой способ. В запросах и ответах для связанных объектов используются их первичные ключи (ID). Это эффективно и минимизирует объем данных.from rest_framework import serializers from .models import Author, Book class BookSerializer(serializers.ModelSerializer): # При POST/PUT запросе ожидается список ID авторов: [1, 2, 3] authors = serializers.PrimaryKeyRelatedField( many=True, queryset=Author.objects.all() ) class Meta: model = Book fields = ['id', 'title', 'authors'] -
SlugRelatedField(по строковому полю) Используется, когда нужно представлять связанные объекты по уникальному текстовому полю (например,usernameилиname) вместо ID.class BookSerializer(serializers.ModelSerializer): # Ожидается список имен авторов: ["Author Name 1", "Author Name 2"] authors = serializers.SlugRelatedField( many=True, slug_field='name', queryset=Author.objects.all() ) class Meta: model = Book fields = ['id', 'title', 'authors'] -
Вложенный сериализатор (полное представление) Позволяет включить полную информацию о связанных объектах. Удобно для чтения (GET), но усложняет запись (POST/PUT), так как требует специальной обработки.
class AuthorSerializer(serializers.ModelSerializer): class Meta: model = Author fields = ['id', 'name'] class BookSerializer(serializers.ModelSerializer): # В ответе будет полный список объектов авторов authors = AuthorSerializer(many=True, read_only=True) # read_only упрощает реализацию class Meta: model = Book fields = ['id', 'title', 'authors']
Запись данных (Create/Update)
При использовании вложенных сериализаторов для записи необходимо переопределить методы .create() или .update() в сериализаторе, чтобы вручную обработать сохранение M2M-связей после создания основного объекта.
Ответ 18+ 🔞
Так, слушай, тут народ часто в ступор входит, когда в DRF надо с полями ManyToMany работать. Типа, ну как их, блядь, сериализовать-то? А вариантов, оказывается, дохуя! Выбирай, как тебе удобнее данные представлять: по ID, по имени или вообще вложенным объектом целиком.
Варианты, которые есть:
-
PrimaryKeyRelatedField(по ID) Самый простой и тупой, как пробка. В запросах и ответах ты будешь видеть только IDшники связанных объектов. Экономно и быстро, но не очень информативно, если хочешь сразу имя увидеть.from rest_framework import serializers from .models import Author, Book class BookSerializer(serializers.ModelSerializer): # Когда будешь POST/PUT делать, шли сюда список ID авторов: [1, 2, 3] authors = serializers.PrimaryKeyRelatedField( many=True, queryset=Author.objects.all() ) class Meta: model = Book fields = ['id', 'title', 'authors'] -
SlugRelatedField(по какому-то текстовому полю) А вот это уже интереснее. Если ID — это для машин, то тут можно показывать людям что-то понятное, например, имя автора. Главное, чтобы поле было уникальным, а то пиздец начнётся.class BookSerializer(serializers.ModelSerializer): # Теперь ждём список имён: ["Лев Толстой", "Фёдор Достоевский"] authors = serializers.SlugRelatedField( many=True, slug_field='name', # Указываешь, по какому полю цепляться queryset=Author.objects.all() ) class Meta: model = Book fields = ['id', 'title', 'authors'] -
Вложенный сериализатор (полный разворот) Ну а это, блядь, для красоты и полного счастья. В ответе получишь не просто ID или имя, а целый объект автора со всеми его полями. Для чтения (GET) — охуенно. Для записи (POST/PUT) — уже сложнее, потому что DRF сам с этим не справится, придётся руки марать.
class AuthorSerializer(serializers.ModelSerializer): class Meta: model = Author fields = ['id', 'name'] class BookSerializer(serializers.ModelSerializer): # Вуаля! В ответе полный список авторов как объектов authors = AuthorSerializer(many=True, read_only=True) # read_only ставим, чтобы не ебаться с записью пока что class Meta: model = Book fields = ['id', 'title', 'authors']
Про запись данных (Create/Update) — отдельная песня
Если выбрал вложенный сериализатор и хочешь через него же и создавать/обновлять, то готовься к ручному труду. Придётся переопределять методы .create() и .update() в сериализаторе, потому что после создания основной модели (книги) нужно вручную, блядь, прописывать все эти M2M-связи с авторами. Иначе нихуя не сохранится.