Django Rest Framework writtable nested serializers

j'écris un organisateur de recettes comme exemple de projet pour une classe. Je ne suis pas très expérimenté avec DRF autre que l'utilisation d'une fonctionnalité très basique. Voici l'objectif:

créer une nouvelle recette avec les ingrédients associés. Créez les objets Ingredient en même temps que L'objet Recipe.

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

cela crée avec succès L'objet Recipe et les objets Ingredients dans la base de données, mais n'associe pas la liste des ingrédients avec la recette. Je suppose que c'est parce que quand je lance ingredients_data = validated_data.pop('ingredients'), le validated_data dictionnaire obtient ses Ingrédients supprimé, donc quand je crée une nouvelle Recette à l'aide de validated_data, il n'y a pas d'ingrédients associés.

cependant, je ne vois pas comment conserver les ingrédients associés à la recette.

24
demandé sur bobbyz 2015-01-22 01:33:05

2 réponses

j'ai compris que de nombreuses relations ne peuvent pas être établies tant que tous les objets non créés n'ont pas été créés. (Voir le Django Docs page sur plusieurs-à-plusieurs liens.)

voici le code de travail:

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

mise à jour:

à la demande de @StevePiercy, voici mon update() code. Toutefois, Je n'ai pas regardé cela depuis des années et n'ai aucune idée si elle est correcte ou bonne. Je n'ai pas travaillé en Python ou Django depuis un certain temps maintenant, alors prenez ceci avec un grain de sel:

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
28
répondu bobbyz 2018-03-09 04:43:46

C'est un petit exemple avec cette question.

changez cette partie du code par ceci.

    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

et c'est la méthode pour éditer, provoquer une erreur quand vous voulez éditer.

    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

Voici un lien avec un exemple, ce code est similaire à un autre réponses, mais si vous voulez essayer le code, sans problème ici est le repo. Bonne chance! DRF serializers imbriqués

6
répondu fercreek 2015-10-14 09:40:01