django rest框架:如何不允许对嵌套的序列化器数据进行验证?

时间:2018-09-23 11:30:06

标签: python django django-models django-rest-framework

我有一个模型BookSerializer的串行器Book和一个嵌套的PageSerializer模型Page。更新Book实例包括删除其所有Page实例,然后创建这些Page实例,可能有或没有这种涉及页面的新数据或没有或没有现有数据的更新。

但是我的Book模型具有一个约束,其中每个Book实例每个最多只能有100个页面。验证检查是在PageSerializer的{​​{1}}方法中完成的。我还有另一个理由在这里这样做:

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): ... ... 方法内以validated_data的方式访问。

现在,这是问题所在。嵌套的序列化器update具有PageSerializer方法,该方法检查该validate实例中已有多少页并针对它们进行验证。

Book是已经拥有B页的Book的实例。如果我尝试对100进行审核,而没有进行任何更改,则仍会在B中检查发送的数据是否经过验证,将其页面数据传递给BookSerializer,然后最终传递PageSerializervalidated_data方法。

我的问题是:

  • 在验证为更新update(self, instance, val;idated_data)发送的页面的数据之前,如何删除B的所有页面?
  • 或者如何绕过嵌套序列化程序的验证?在保存之前,只验证序列化程序,并会在父序列化程序的update方法内部进行嵌套序列化程序的验证。

1 个答案:

答案 0 :(得分:0)

我建议您使用BookSerializer的update(**kwargs)方法删除页面。在PageSerializer的验证方法中,您应该验证收到的数据(您不应将现有的页面视为要删除所有页面的顺序)。仅完全覆盖现有书籍的页面就是这种情况。但是,当您要更新它们时,还应该返回id页(您应该在id中添加PageSerializer,以便嵌套的序列化程序可以标识您正在更新的实例)。因此,需要进行验证才能更新。

请求正文应如下所示:

{
   '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

使用批量或迭代进行简单创建。