首页 文章

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

提问于
浏览
0

我有一个模型 Book 的序列化程序 BookSerializer ,其中嵌套了 PageSerializer 型号为 Page . 更新 Book 实例涉及删除其所有 Page 实例,然后创建这些 Page 实例,可能有或没有涉及页面的新数据或没有或存在的此更新 .

但是我的 Book 模型有一个约束,其中每个 Book 实例每个只能有最多 100 个页面 . 验证检查在 PageSerializervalidate 方法内完成 . 我有另一个理由在这里这样做:

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 是已经 100 页的 Book 的实例 . 如果我尝试在没有任何更改的情况下更新 B ,则仍会在 BookSerializer 中检查发送的数据以进行验证,将其页面数据传递给 PageSerializer ,然后最终将 validated_data 传递给 update(self, instance, val;idated_data) 方法 .

我的问题是:

  • 如何在验证为更新 B 而发送的页面数据之前删除 B 的所有页面?

  • 或者如何绕过嵌套序列化程序的验证?仅验证序列化程序,并在保存之前处理父序列化程序的更新方法中嵌套序列化程序的验证 .

1 回答

  • 0

    我建议你删除BookSerializer的 update(**kwargs) 方法中的页面 . 在 PageSerializer 的验证方法中,您应验证收到的数据(您不应将现有页面视为序列,您将 delete all them ) . 这是仅完全覆盖现有书籍页面的情况 . 但是当您想要更新它们时,您还应该返回 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
    

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

相关问题