Django DRF - 如何反序列化需要外键的实例?
Django DRF - how to deserialize an instance that requires a foreign key?
我有一个页面模型和一个引用其页面的段落模型。我想通过反序列化 JSON 表示来创建这两个模块,如下所示:
{
"page": {
"number": 32,
"book": "Moby Dick",
"paragraphs": [
{
"label": "I am a Paragraph within the Page"
}
]
}
}
这是我的段落和页面模型:
class Paragraph(models.Model):
page = models.ForeignKey(
Page,
help_text="Every Paragraph must belong to a Page",
related_name="paragraphs",
on_delete=models.CASCADE,
)
label = models.CharField(max_length=128)
class Meta:
db_table = 'my_paragraph'
class Page(models.Model):
# This is not unique!
number = models.IntegerField()
# This is not unique!
book = models.CharField(max_length=128)
# but "number" and "book" together are unique.
class Meta:
db_table = 'my_page'
如何反序列化该表示以实例化我的模型?
我尝试在下面创建这些序列化程序:
class ParagraphSerializer (serializers.ModelSerializer):
page = serializers.SlugRelatedField(
slug_field="id",
queryset=models.Page.objects.all(),
)
class Meta:
model = models.Paragraph
fields = '__all__'
class PageSerializer (serializers.ModelSerializer):
paragraphs = ParagraphSerializer(
many=True,
)
# This method never gets called, because PageSerializer validation fails.
def create(self, validated_data):
paragraphs_data = validated_data.pop('paragraphs')
page = models.Page.objects.create(**validated_data)
for paragraph_data in paragraphs_data:
# We'll need to find some way of adding a `page` field to this paragraph...
paragraph_data['page'] = page.id
serializer = ParagraphSerializer(data=paragraph_data)
serializer.is_valid()
serializer.save()
class Meta:
model = models.Page
fields = '__all__'
但是我遇到了错误,因为 SlugRelatedField
需要我的 paragraph
JSON 来引用它的页面:
serializer = PageSerializer(data=page_json)
serializer.is_valid()
# is_valid() fails with the following message:
# [{'paragraphs': [{'page': [u'This field is required.']}]}, {}]
我是否应该尝试将 page
字段添加到我的 paragraphs
JSON,如果是,我应该使用哪个 slug_field
?不幸的是,Page 上唯一的唯一字段是 id
。但是book
和number
的复合键是唯一的
或者有没有办法让is_valid()
传递我的PageSerializer,这样我们就可以在PageSerializer.create
方法中指定paragraph
模型上的page
字段?
我能够通过从我的 ParagraphSerializer
中删除 page
属性并在 ParagraphSerializer.create
方法中手动设置它来解决这个问题。
这可以通过将我的 Page 模型传递给序列化程序的上下文对象来实现,如下所示:
class ParagraphSerializer (serializers.ModelSerializer):
class Meta:
model = models.Paragraph
exclude = 'page'
def create(self, validated_data):
return models.Paragraph.objects.create(
page=self.context.get("page"),
**validated_data
)
class PageSerializer (serializers.ModelSerializer):
paragraphs = ParagraphSerializer(
many=True,
)
class Meta:
model = models.Page
fields = '__all__'
def create(self, validated_data):
paragraphs_data = validated_data.pop('paragraphs')
page = models.Page.objects.create(**validated_data)
for paragraph_data in paragraphs_data:
# We'll need to find some way of adding a `page` field to this paragraph...
paragraph_data['page'] = page.id
serializer = ParagraphSerializer(
data=paragraph_data,
context={"page": page}
)
serializer.is_valid()
serializer.save()
return page
我不必更改我的模型,也不必更改我的 JSON 表示!
当我看到这个博客 post 时,一切都变得有意义了,这有助于描述通过序列化程序 create
方法传递 context
对象的可能性:
https://micropyramid.com/blog/django-rest-framework-send-extra-context-data-to-serializers/
我有一个页面模型和一个引用其页面的段落模型。我想通过反序列化 JSON 表示来创建这两个模块,如下所示:
{
"page": {
"number": 32,
"book": "Moby Dick",
"paragraphs": [
{
"label": "I am a Paragraph within the Page"
}
]
}
}
这是我的段落和页面模型:
class Paragraph(models.Model):
page = models.ForeignKey(
Page,
help_text="Every Paragraph must belong to a Page",
related_name="paragraphs",
on_delete=models.CASCADE,
)
label = models.CharField(max_length=128)
class Meta:
db_table = 'my_paragraph'
class Page(models.Model):
# This is not unique!
number = models.IntegerField()
# This is not unique!
book = models.CharField(max_length=128)
# but "number" and "book" together are unique.
class Meta:
db_table = 'my_page'
如何反序列化该表示以实例化我的模型?
我尝试在下面创建这些序列化程序:
class ParagraphSerializer (serializers.ModelSerializer):
page = serializers.SlugRelatedField(
slug_field="id",
queryset=models.Page.objects.all(),
)
class Meta:
model = models.Paragraph
fields = '__all__'
class PageSerializer (serializers.ModelSerializer):
paragraphs = ParagraphSerializer(
many=True,
)
# This method never gets called, because PageSerializer validation fails.
def create(self, validated_data):
paragraphs_data = validated_data.pop('paragraphs')
page = models.Page.objects.create(**validated_data)
for paragraph_data in paragraphs_data:
# We'll need to find some way of adding a `page` field to this paragraph...
paragraph_data['page'] = page.id
serializer = ParagraphSerializer(data=paragraph_data)
serializer.is_valid()
serializer.save()
class Meta:
model = models.Page
fields = '__all__'
但是我遇到了错误,因为 SlugRelatedField
需要我的 paragraph
JSON 来引用它的页面:
serializer = PageSerializer(data=page_json)
serializer.is_valid()
# is_valid() fails with the following message:
# [{'paragraphs': [{'page': [u'This field is required.']}]}, {}]
我是否应该尝试将 page
字段添加到我的 paragraphs
JSON,如果是,我应该使用哪个 slug_field
?不幸的是,Page 上唯一的唯一字段是 id
。但是book
和number
的复合键是唯一的
或者有没有办法让is_valid()
传递我的PageSerializer,这样我们就可以在PageSerializer.create
方法中指定paragraph
模型上的page
字段?
我能够通过从我的 ParagraphSerializer
中删除 page
属性并在 ParagraphSerializer.create
方法中手动设置它来解决这个问题。
这可以通过将我的 Page 模型传递给序列化程序的上下文对象来实现,如下所示:
class ParagraphSerializer (serializers.ModelSerializer):
class Meta:
model = models.Paragraph
exclude = 'page'
def create(self, validated_data):
return models.Paragraph.objects.create(
page=self.context.get("page"),
**validated_data
)
class PageSerializer (serializers.ModelSerializer):
paragraphs = ParagraphSerializer(
many=True,
)
class Meta:
model = models.Page
fields = '__all__'
def create(self, validated_data):
paragraphs_data = validated_data.pop('paragraphs')
page = models.Page.objects.create(**validated_data)
for paragraph_data in paragraphs_data:
# We'll need to find some way of adding a `page` field to this paragraph...
paragraph_data['page'] = page.id
serializer = ParagraphSerializer(
data=paragraph_data,
context={"page": page}
)
serializer.is_valid()
serializer.save()
return page
我不必更改我的模型,也不必更改我的 JSON 表示!
当我看到这个博客 post 时,一切都变得有意义了,这有助于描述通过序列化程序 create
方法传递 context
对象的可能性:
https://micropyramid.com/blog/django-rest-framework-send-extra-context-data-to-serializers/