问题描述
我有模型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
并使用批量或迭代进行简单创建。