J'écris un organisateur de recettes comme exemple de projet pour une classe. Je ne suis pas très expérimenté avec DRF à part utiliser des fonctionnalités très basiques. Voici l'objectif:
Créez une nouvelle recette avec les ingrédients associés. Créez les objets Ingrédient en même temps que la création de l'objet Recette.
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 Recette ET les objets Ingrédients dans la base de données, mais n'associe pas la liste des ingrédients à la recette. Je suppose que c'est parce que lorsque j'exécute ingredients_data = validated_data.pop('ingredients')
, le dictionnaire validated_data
Obtient ses ingrédients supprimés, donc quand je crée une nouvelle recette en utilisant validated_data
, Il n'y a pas d'ingrédients associés .
Cependant, je n'arrive pas à trouver un moyen de conserver les ingrédients associés à la recette.
J'ai compris que les relations ManyToMany ne peuvent pas être établies tant que tous les objets non créés n'ont pas été créés. (Voir les Django Docs page sur les relations plusieurs-à-plusieurs .))
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
Par demande de @StevePiercy, voici mon code update()
. Cependant , je n'ai pas regardé cela depuis des années et je n'ai aucune idée que ce soit correct ou bon. Je ne travaille pas depuis 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
Ceci est un petit exemple avec cette question.
Modifiez 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 lorsque vous souhaitez é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 voici le repo. Bonne chance! sérialiseurs imbriqués DRF