问题描述
我有模型Book
的序列化BookSerializer
PageSerializer
和模型Page
的嵌套PageSerializer
。
更新Book
实例涉及删除其所有Page
实例,然后创建这些Page
实例,可能有或没有这种涉及某些新页面数据或没有或没有现有数据的更新。
但是我的Book
模型有一个约束,其中每个Book
实例每个最多只能有100
页。
验证检查是在PageSerializer
的validate
方法内部完成的。
我还有另一个理由在这里这样做:
def validate(self, attrs):
#some logic here
raise some error if book instance already has 100 pages or if it will have more than 100 pages when combined with new pages when added.
序列化器或说BookSerializer
的更新方法定义为:
def update(self, instance, validated_data):
...
...
因此,发送给更新的数据已经过验证,可以在update
方法中作为validated_data
进行访问。
现在,这就是问题所在。
嵌套的序列化程序PageSerializer
有一个validate
方法,该方法检查该Book
实例中已经有多少页并对它们进行验证。
令B
为Book
的实例,该实例已经有100
页。
如果我尝试对B
进行审核,则BookSerializer
检查发送的数据是否经过验证,将其页面数据传递给PageSerializer
,然后最后将validated_data
传递给update(self, instance, val;idated_data)
方法。
我的问题是:
-
在验证为更新
B
发送的页面数据之前,如何删除B
所有页面? - 或如何绕过嵌套序列化程序的验证? 在保存之前,仅验证序列化程序,并会在父序列化程序的update方法内进行嵌套序列化程序的验证。
1楼
我建议您删除BookSerializer的update(**kwargs)
方法中的页面。
在PageSerializer
验证方法中,您应该验证接收到的数据(不应将现有页面视为一个序列,而将其全部删除 )。
仅完全覆盖现有书籍的页面就是这种情况。
但是,当您要更新它们时,还应该返回页面的id
(您应该在PageSerializer
中添加id
,以便嵌套的序列化程序可以标识您正在更新实例)。
因此,需要进行验证才能进行更新。
请求正文应如下所示:
{
'book_title': 'TITLE'
'pages':[
{'id': 3, 'title': 'TITLE', 'body': 'BODY'},
{'title': 'TITLE', 'body': 'BODY'}, ...
]
....
}
class PageSerializer(serializers.ModelSerializer):
class Meta:
model = Page
fields =['id', .....]
class Book(serializers.ModelSerializer):
pages = PageSerializer(many=True)
class Meta:
model = Book
fields = ['id', 'pages', ....]
def validate_pages(self, values): # here values will be as [{...},{...},..]
obj_list = list()
for value in values:
pk = value.pop('id', None)
if pk:
try:
page = Page.objects.get(pk=pk)
for k, v in value.items():
setattr(page, key, value)
obj_list.append(page)
except Page.DoesNotExists():
# handle by yourself, skip or raise error
else:
obj_list.append(Page(**value))
# here you can validate length also
return obj_list
在create(self, validated_data)
和update(self, instance, validated_data)
您将页面作为对象列表。
因此,您可以使用以下方法删除:
pages = validated_data['pages']
page_ids = [page.pk for page in pages if page.pk] # it get all ids from list
if page_ids:
Page.objects.filter(book=instance).exclude(pk__in=page_ids).delete() it can be applicable only for updating
并使用批量或迭代进行简单创建。