Я бы написал так:
models.pyfrom django.db import models
class Ingridient(models.Model):
name = models.CharField(
max_length=30,
unique=True,
db_index=True
)
class Meta:
db_table = 'ingridient'
ordering = [ 'name' ]
class Recipe(models.Model):
name = models.CharField(
max_length=30,
unique=True,
db_index=True
)
ingridients = models.ManyToManyField(
Ingridient
)
class Meta:
db_table = 'recipe'
ordering = [ 'name' ]
serializers.pyfrom rest_framework.serializers import ModelSerializer, PrimaryKeyRelatedField
from .models import Ingridient, Recipe
class IngridientSerializer(ModelSerializer):
class Meta:
model = Ingridient
class RecipeReadListSerializer(ModelSerializer):
class Meta:
model = Recipe
exclude = ['ingridients']
class RecipeReadDetailSerializer(ModelSerializer):
ingridients = IngridientSerializer(
many=True
)
class Meta:
model = Recipe
class RecipeWriteSerializer(ModelSerializer):
ingridients = PrimaryKeyRelatedField(
queryset=Ingridient.objects.all(),
many=True,
default=[]
)
class Meta:
model = Recipe
views.pyfrom rest_framework.viewsets import ModelViewSet
from .serializers import IngridientSerializer, RecipeReadListSerializer, RecipeReadDetailSerializer, RecipeWriteSerializer
from .models import Ingridient, Recipe
from rest_framework.permissions import AllowAny
class IngridientViewSet(ModelViewSet):
queryset = Ingridient.objects.all()
serializer_class = IngridientSerializer
permission_classes = [
AllowAny
]
class Meta:
model = Ingridient
class RecipeViewSet(ModelViewSet):
queryset = Recipe.objects.all()
permission_classes = [
AllowAny
]
def get_serializer_class(self):
if self.request.method == 'GET':
if self.action == 'list':
return RecipeReadListSerializer
return RecipeReadDetailSerializer
return RecipeWriteSerializer
urls.pyfrom rest_framework.routers import SimpleRouter
from .views import IngridientViewSet, RecipeViewSet
router = SimpleRouter()
router.register(r'ingridients', IngridientViewSet, base_name='ingridients')
router.register(r'recipies', RecipeViewSet, base_name='recipe')
urlpatterns = router.urls
Насчёт использования
SlugField не совсем уверен, что они нужны, ведь API в данном случае будет простым, список его URL вообще проще некуда, впрочем, я думаю, добавить их вы сможете в любое нужное время.
Зачем для сериализации рецептов целых три сериализатора?
При получении списка всех рецептов как правило не нужно сразу же получать и все ингридиенты. Во всяком случае, в моих приложениях я делаю подгрузку полной копии модели только при детальном просмотре, а в списках часть полей скрыта на уровне API. Надо ли говорить, что при сериализации пользователей несколько сериализаторов просто необходимы, чтобы не выводить пароль при получении объекта, но иметь возможность его обновлять при записи?
Сериализатор для чтения деталей как раз выдаёт вложенные объекты при получении модели рецепта - в поле
ingridients будет массив полностью сериализованных объектов
Ingridient.
Третий сериализатор используется только для создания записей типа
Recipe или их обновления. Для заполнения ингридиентов нужно передать список их id. DRF сам проверит существование соответствующих моделей и выполнит все остальные действия.