Python Django Rest Framework 可写嵌套序列化程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28078092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Django Rest Framework writable nested serializers
提问by bobbyz
I'm writing a recipe organizer as a sample project for a class. I'm not very experienced with DRF other than using some very basic functionality. Here's the objective:
我正在编写一个食谱组织者作为一个班级的示例项目。除了使用一些非常基本的功能之外,我对 DRF 的经验并不多。这是目标:
Create a new Recipe with associated Ingredients. Create the Ingredient objects at the same time as creating the Recipe object.
使用相关成分创建新配方。在创建 Recipe 对象的同时创建 Ingredient 对象。
models.py:
模型.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
序列化程序.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
This successfully creates the Recipe object AND the Ingredients objects in the database, but doesn't associate the list of Ingredients with the Recipe. I assume this is because when I run ingredients_data = validated_data.pop('ingredients')
, the validated_data
dictionary gets its Ingredients removed, so when I create a new Recipe using validated_data
, there aren't associated ingredients.
这成功地在数据库中创建了配方对象和成分对象,但不会将成分列表与配方相关联。我认为这是因为当我运行时ingredients_data = validated_data.pop('ingredients')
,validated_data
字典删除了它的成分,所以当我使用创建一个新的 Recipe 时validated_data
,没有关联的成分。
However I can't seem to figure out a way to keep ingredients associated with the recipe.
但是,我似乎无法找到一种方法来保持与食谱相关的成分。
采纳答案by bobbyz
I figured out that ManyToMany relationships can't be established until all of the uncreated objects have been created. (See the Django Docs page on many-to-many relationships.)
我发现在创建所有未创建的对象之前无法建立多对多关系。(请参阅关于多对多关系的 Django 文档页面。)
Here's the working code:
这是工作代码:
serializers.py
序列化程序.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
UPDATE:
更新:
Per request of @StevePiercy, below is my update()
code. However, I haven't looked at this in years and have no idea whatsoever if it is correct or good. I haven't been working in Python or Django for some time now, so take this with a grain of salt:
根据@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
回答by fercreek
Below is a helpful example for this question.
下面是这个问题的一个有用的例子。
Change that part of code like this:
像这样更改那部分代码:
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
And this is the method to edit, cause an error when you want to edit.
这就是编辑的方法,当你想编辑时会导致错误。
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
Here is a link with an example. This code is similar to another answer, but if you want to try the code without any problems, you can use this repo. Good luck! DRF Nested serializers
这是一个带有示例的链接。此代码类似于另一个答案,但如果您想尝试该代码而没有任何问题,则可以使用此 repo。祝你好运! DRF 嵌套序列化程序