web-dev-qa-db-ja.com

Django Rest Framework書き込み可能なネストされたシリアライザー

クラスのサンプルプロジェクトとしてレシピオーガナイザーを書いています。いくつかの非常に基本的な機能を使用する以外は、DRFの経験はあまりありません。目的は次のとおりです。

関連する成分を含む新しいレシピを作成します。レシピオブジェクトの作成と同時に、成分オブジェクトを作成します。

models.py:

_class Ingredient(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class Recipe(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True, null=True, help_text="This is a quick description of your recipe")
    directions = models.TextField(help_text="How to make the recipe")
    ingredients = models.ManyToManyField(Ingredient)

    def __str__(self):
        return self.name
_


serializers.py

_class IngredientSerializer(serializers.ModelSerializer):

    class Meta:
        model = Ingredient


class RecipeSerializer(serializers.ModelSerializer):
    ingredients = IngredientSerializer(many=True)

    class Meta:
        model = Recipe

    def create(self, validated_data):
        ingredients_data = validated_data.pop('ingredients')
        recipe = Recipe.objects.create(**validated_data)
        for ingredient_data in ingredients_data:
            Ingredient.objects.create(**ingredient_data)
        return recipe
_

これにより、RecipeオブジェクトとIngredientsオブジェクトがデータベースに正常に作成されますが、IngredientsのリストはRecipeに関連付けられません。これは、ingredients_data = validated_data.pop('ingredients')を実行すると_validated_data_辞書の成分が削除されるため、_validated_data_を使用して新しいレシピを作成すると、関連する成分がないためだと思います。

ただし、レシピに関連する材料を保持する方法を理解できないようです。

36
bobbyz

未作成のオブジェクトがすべて作成されるまで、ManyToMany関係を確立できないことがわかりました。 (Django Docs 多対多の関係のページ を参照してください。)

作業コードは次のとおりです。

serializers.py

_class RecipeSerializer(serializers.ModelSerializer):
    ingredients = IngredientSerializer(many=True)

    class Meta:
        model = Recipe

    def create(self, validated_data):
        ingredients_data = validated_data.pop('ingredients')
        recipe = Recipe.objects.create(**validated_data)

        for ingredient in ingredients_data:
            ingredient, created = Ingredient.objects.get_or_create(name=ingredient['name'])
            recipe.ingredients.add(ingredient)
        return recipe
_

更新:

@StevePiercyのリクエストごとに、以下は私のupdate()コードです。 しかし、、私はこれを何年も見ていないし、それが正しいか良いかどうか全くわからない。私はPythonまたはDjangoでしばらく働いていませんでした。

_def update(self, instance, validated_data):
    ingredients_data = validated_data.pop('ingredients')

    instance.name = validated_data.get('name', instance.name)
    instance.description = validated_data.get('description', instance.description)
    instance.directions = validated_data.get('directions', instance.directions)
    instance.photo = validated_data.get('photo', instance.photo)

    ingredients_list = []

    for ingredient in ingredients_data:
        ingredient, created = Ingredient.objects.get_or_create(name=ingredient["name"])
        ingredients_list.append(ingredient)

    instance.ingredients = ingredients_list
    instance.save()
    return instance
_
38
bobbyz

これは、この質問の小さな例です。

これによりコードのその部分を変更します。

    def create(self, validated_data):
        ingredients_data = validated_data.pop('ingredients')
        recipe = Recipe.objects.create(**validated_data)

        for ingredient in ingredients_data:
            ingredient, created = Ingredient.objects.get_or_create(name=ingredient['name'])
            recipe.ingredients.add(ingredient)
        return recipe

そして、これは編集する方法であり、編集したいときにエラーを引き起こします。

    def update(self, instance, validated_data):
        ingredients_data = validated_data.pop('ingredients')
        instance.name = validated_data['name']
        instance.description = validated_data['description']
        instance.directions = validated_data['directions']

        for ingredient in ingredients_data:
            ingredient, created = Ingredient.objects.get_or_create(name=ingredient['name'])
            recipe.ingredients.add(ingredient)
        return instance

例とのリンクは、このコードは別の答えに似ていますが、コードを試してみたい場合は、ここに問題なくレポがあります。がんばろう! DRFネストされたシリアライザー

9
fercreek