Python django-rest-framework 3.0 在嵌套序列化程序中创建或更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27434593/
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 3.0 create or update in nested serializer
提问by norbert
With django-rest-framework 3.0and having these simple models:
使用django-rest-framework 3.0并拥有这些简单的模型:
class Book(models.Model):
title = models.CharField(max_length=50)
class Page(models.Model):
book = models.ForeignKey(Books, related_name='related_book')
text = models.CharField(max_length=500)
And given this JSON request:
并给出这个 JSON 请求:
{
"book_id":1,
"pages":[
{
"page_id":2,
"text":"loremipsum"
},
{
"page_id":4,
"text":"loremipsum"
}
]
}
How can I write a nested serializer to process this JSON and for each pagefor the given bookeither create a new page or update if it exists.
如何编写嵌套序列化程序来处理此 JSON,并为page给定的book每个创建一个新页面或更新(如果存在)。
class RequestSerializer(serializers.Serializer):
book_id = serializers.IntegerField()
page = PageSerializer(many=True)
class PageSerializer(serializers.ModelSerializer):
class Meta:
model = Page
I know that instantiating the serializer with an instancewill update the current one but how should I use it inside the createmethod of nested serializer?
我知道用 an 实例化序列化器instance会更新当前的序列化器,但是我应该如何在create嵌套序列化器的方法中使用它?
采纳答案by Tom Christie
Firstly, do you want to support creating new book instances, or only updating existing ones?
首先,您是要支持创建新的图书实例,还是仅更新现有的图书实例?
If you only ever wanted to create new book instances you could do something like this...
如果你只想创建新书实例,你可以做这样的事情......
class PageSerializer(serializers.Serializer):
text = serializers.CharField(max_length=500)
class BookSerializer(serializers.Serializer):
page = PageSerializer(many=True)
title = serializers.CharField(max_length=50)
def create(self, validated_data):
# Create the book instance
book = Book.objects.create(title=validated_data['title'])
# Create or update each page instance
for item in validated_data['pages']:
page = Page(id=item['page_id'], text=item['text'], book=book)
page.save()
return book
Note that I haven'tincluded the book_idhere. When we're creating book instances we won't be including a book id. When we're updating book instances we'll typically include the book id as part of the URL, rather than in the request data.
请注意,我没有包括在book_id这里。当我们创建书籍实例时,我们不会包含书籍 ID。当我们更新图书实例时,我们通常会将图书 ID 作为 URL 的一部分,而不是包含在请求数据中。
If you want to support both create and update of book instances then you need to think about how you want to handle pages that are not included in the request, but arecurrently associated with the book instance.
如果你想支持创建和书籍实例的更新,那么你需要考虑一下你要如何处理未包含在请求页面,但在当前与书实例相关联。
You might choose to silently ignore those pages and leave them as they are, you might want to raise a validation error, or you might want to delete them.
您可能会选择默默地忽略这些页面并保持原样,您可能想要引发验证错误,或者您可能想要删除它们。
Let's assume that you want to delete any pages not included in the request.
假设您要删除请求中未包含的任何页面。
def create(self, validated_data):
# As before.
...
def update(self, instance, validated_data):
# Update the book instance
instance.title = validated_data['title']
instance.save()
# Delete any pages not included in the request
page_ids = [item['page_id'] for item in validated_data['pages']]
for page in instance.books:
if page.id not in page_ids:
page.delete()
# Create or update page instances that are in the request
for item in validated_data['pages']:
page = Page(id=item['page_id'], text=item['text'], book=instance)
page.save()
return instance
It's also possible that you might want to onlysupport book updates, and not support creation, in which case, onlyinclude the update()method.
也有可能,你可能希望只支持本书的更新,而不是支持创作,在这种情况下,仅包括update()方法。
There are also various ways you could reduce the number of queries eg. using bulk create/deletion, but the above would do the job in a fairly straightforward way.
还有多种方法可以减少查询次数,例如。使用批量创建/删除,但上面的方法会以相当简单的方式完成这项工作。
As you can see there are subtleties in the types of behavior you might want when dealing with nested data, so think carefully about exactly what behavior you're expecting in various cases.
正如您所看到的,在处理嵌套数据时您可能想要的行为类型存在微妙之处,因此请仔细考虑在各种情况下您期望的行为。
Also note that I've been using Serializerin the above example rather than ModelSerializer. In this case it's simpler just to include all the fields in the serializer class explicitly, rather than relying on the automatic set of fields that ModelSerializergenerates by default.
另请注意,我Serializer在上面的示例中一直使用而不是ModelSerializer. 在这种情况下,只需显式包含序列化程序类中的所有字段,而不是依赖ModelSerializer默认情况下生成的自动字段集,就更简单了。
回答by Peter Sobhi
You can simply use drf-writable-nested. It automatically make your nested serializers writable and updatable.
您可以简单地使用drf-writable-nested。它会自动使您的嵌套序列化程序可写和可更新。
in you serializers.py:
在你serializers.py:
from drf_writable_nested import WritableNestedModelSerializer
class RequestSerializer(WritableNestedModelSerializer):
book_id = serializers.IntegerField()
page = PageSerializer(many=True)
class PageSerializer(serializers.ModelSerializer):
class Meta:
model = Page
And that's it!
就是这样!
Also the library supports using only one of the createand updatelogics if you don't need both.
如果您不需要两者,该库也支持仅使用create和update逻辑之一。

