Django Rest Framework 可写嵌套序列化程序
Django Rest Framework writable nested serializers
我正在编写一个食谱组织器作为 class 的示例项目。除了使用一些非常基本的功能外,我对 DRF 不是很有经验。这是 objective:
创建一个包含相关成分的新食谱。在创建 Recipe 对象的同时创建 Ingredient 对象。
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
创建新食谱时,没有相关成分.
但是我似乎无法找到一种方法来使配料与食谱相关联。
我发现在创建所有未创建的对象之前无法建立多对多关系。 (参见 Django 文档 page on many-to-many relationships。)
这是工作代码:
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
下面是这个问题的有用示例。
像这样更改那部分代码:
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
这里有一个 link 示例。此代码类似于另一个答案,但如果您想毫无问题地尝试该代码,您可以使用此 repo。祝你好运!
DRF Nested serializers
我正在编写一个食谱组织器作为 class 的示例项目。除了使用一些非常基本的功能外,我对 DRF 不是很有经验。这是 objective:
创建一个包含相关成分的新食谱。在创建 Recipe 对象的同时创建 Ingredient 对象。
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
创建新食谱时,没有相关成分.
但是我似乎无法找到一种方法来使配料与食谱相关联。
我发现在创建所有未创建的对象之前无法建立多对多关系。 (参见 Django 文档 page on many-to-many relationships。)
这是工作代码:
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
下面是这个问题的有用示例。
像这样更改那部分代码:
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
这里有一个 link 示例。此代码类似于另一个答案,但如果您想毫无问题地尝试该代码,您可以使用此 repo。祝你好运! DRF Nested serializers