Reputation: 63
I am trying to update submitted data by implementing the update() method on the a SerializerClass. However i do not know how to get access to the current ingredient of the current instance and also i do not know how to iterate through the validated data such that i can assign the key and values correctly. any advice would be appreciated!
My Serializer
class RecipeSerializer(ModelSerializer):
ingredients = IngredientSerializer(many=True)
owner = ReadOnlyField(source='owner.username')
class Meta:
fields = ['owner', 'name', 'description', 'image', 'ingredients']
model = Recipe
def create(self, validated_data):
ingredient_datas = validated_data.pop('ingredients')
recipe = Recipe.objects.create(**validated_data)
for ingredient_data in ingredient_datas:
recipe.ingredients.create(**ingredient_data)
return recipe
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.description = validated_data.get('description', instance.description)
instance.image = validated_data.get('image', instance.image)
for ingredient in validated_data.get('ingredients'):
for key, value in ingredient.items():
print(key, value)
instance.ingredient.name = value
instance.ingredient.amount = value
instance.save()
return instance
My Models
class Recipe(models.Model):
owner = models.ForeignKey('auth.User', related_name='recipes', on_delete=models.CASCADE)
name = models.CharField(max_length=100)
description = models.TextField(max_length=200, blank=True)
image = models.CharField(max_length=100, blank=True)
ingredients = models.ManyToManyField(Ingredient, related_name='recipes')
class Ingredient(models.Model):
name = models.CharField(max_length=50)
amount = models.IntegerField(default=1)
Some window shell ouputs
print(validated_data)
{'name': 'bedddef', 'description': 'gdddoot', 'image': 'httpdddlo', 'ingredients': [OrderedDict([('name', 'tomatoes'), ('amount', 2)]), OrderedDict([('name', 'bread'), ('amount', 3)])]}
for key, value in ingredient.items():
print(key, value)
name tomatoes
amount 2
name bread
amount 3
Recently (today) I recreated the entire api again because i lost it. I tried using the same code bear suggested for the update() method using Ingredient.objects.get_or_create() but i got an error saying.
MultipleObjectsReturned at /api/recipes/3/ get() returned more than one Ingredient -- it returned 2!
Because of the error i substituted get_or_create() for just create() would that be a bad solution?
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.descriptions = validated_data.get('descriptions', instance.descriptions)
instance.image = validated_data.get('image', instance.image)
ingredients = []
for ingredient in validated_data.get('ingredients'):
obj = Ingredient.objects.create(**ingredient)
ingredients.append(obj)
print(ingredients)
instance.ingredients.set(ingredients)
instance.save()
return instance
Upvotes: 0
Views: 92
Reputation:
you can use set
method of the m2m RelatedManager
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.description = validated_data.get('description', instance.description)
instance.image = validated_data.get('image', instance.image)
ingredients = []
for ingredient in validated_data.get('ingredients'):
obj, _ = Ingredient.objects.get_or_create(**ingredient)
ingredients.append(obj)
instance.ingredients.set(ingredients)
# ^^^^^^
instance.save()
return instance
details: the get_or_create
return tuple of the model instance and bool value is created new instance, but we don't need the bool, so to do the code more readable just assign the value of the variable _
obj, _ = Ingredient.objects.get_or_create(**ingredient)
Upvotes: 1