Django/DRF

[DRF] nested serializer 사용 방법

Jong_seoung 2024. 7. 3. 13:12
반응형

Nested Serializer 란?

DRF에서 제공하는 기능으로, 관계형 데이터를 처리할 때 매우 유용하다. 이 기능을 이용하여 데이터의 중첩된 관계를 표현하고 관리할 수 있다.

 

Nested Serializer 사용법

코드를 보면 IngredientsSerializer, RecipeProcessSerializer, recipe_comments 세가지 직렬화가 BasicRecipeSerializer에 중첩되어 있는 것을 확인할 수 있다.

like_count와 bookmark_count는 LikeBookmark를 상속받아 중첩시킨 부분이여서 설명에서 제외하였다.

 

주의 깊게 봐야 되는 부분이 create와 update 메서드 부분인데, nested serializer는 읽기 전용 필드 이기 때문에 따로 create와 update부분을 오버라이드해서 처리해주었다.

class RecipeProcessSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)

    class Meta:
        model = RecipeProcess
        fields = ["id", "order", "content", "image"]


class IngredientsSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)

    class Meta:
        model = Ingredients
        fields = ["id", "type", "name", "count", "unit", "etc"]
        

class BasicRecipeSerializer(serializers.ModelSerializer, LikeBookmark):
    user = serializers.StringRelatedField()
    recipe_ingredients = IngredientsSerializer(many=True)
    recipe_process = RecipeProcessSerializer(many=True)
    like_count = serializers.SerializerMethodField(read_only=True)
    bookmark_count = serializers.SerializerMethodField(read_only=True)
    recipe_comments = CommentSerializer(many=True, read_only=True)

    class Meta:
        model = FoodRecipes
        fields = [
            "id",
            "categoryCD",
            "user",
            "title",
            "thumnail",
            "video",
            "intro",
            "time",
            "people_num",
            "difficulty",
            "recipe_ingredients",
            "recipe_process",
            "like_count",
            "bookmark_count",
            "created_at",
            "updated_at",
            "recipe_comments",
        ]

    def create(self, validated_data):
        ingredients_data = validated_data.pop("recipe_ingredients")
        process_datas = validated_data.pop("recipe_process")

        user = self.context.get("request").user

        if isinstance(user, AnonymousUser):
            return print("user not fount")

        validated_data["user"] = user
        recipe = FoodRecipes.objects.create(**validated_data)

        for ingredient_data in ingredients_data:
            Ingredients.objects.create(foodrecipe=recipe, **ingredient_data)
        for process_data in process_datas:
            RecipeProcess.objects.create(foodrecipe=recipe, **process_data)

        return recipe

    def update(self, instance, validated_data):
        ingredients_data = validated_data.pop("recipe_ingredients", "")
        process_datas = validated_data.pop("recipe_process", "")

        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()

        for ingredient_data in ingredients_data:
            try:
                ingredient = Ingredients.objects.get(pk=ingredient_data["id"])
                ingredient.type = ingredient_data.get("type", ingredient.type)
                ingredient.name = ingredient_data.get("name", ingredient.name)
                ingredient.count = ingredient_data.get("count", ingredient.count)
                ingredient.unit = ingredient_data.get("unit", ingredient.unit)
                ingredient.etc = ingredient_data.get("etc", ingredient.etc)
                ingredient.save()

            except Ingredients.DoesNotExist:
                Ingredients.objects.create(**ingredient_data)

        for process_data in process_datas:
            try:
                process = RecipeProcess.objects.get(pk=process_data["pk"])
                process.order = process.get("order", process.order)
                process.image = process.get("image", process.image)
                process.content = process.get("content", process.content)
                process.save()

            except RecipeProcess.DoesNotExist:
                RecipeProcess.objects.create(**process_data)

        return instance

 

겪었던 문제점

  1. 기본적으로 nested serializer는 읽기전용이기 때문에, 모델을 저장, 수정 하려면 create(), update() 메서드를 재정의할 필요가 있다.
  2. drf-ysag에서 mutipart/form-data와 nested serializer을 동시에 사용하는 것이 불가능하여 postman으로 api 문서화를 진행하였다.

 

반응형