当前位置: 代码迷 >> python >> django rest框架:如何不允许对嵌套的序列化器数据进行验证?
  详细解决方案

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

热度:66   发布时间:2023-07-14 09:49:06.0

我有模型Book的序列化BookSerializer PageSerializer和模型Page的嵌套PageSerializer 更新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实例中已经有多少页并对它们进行验证。

BBook的实例,该实例已经有100页。 如果我尝试对B进行审核,则BookSerializer检查发送的数据是否经过验证,将其页面数据传递给PageSerializer ,然后最后将validated_data传递给update(self, instance, val;idated_data)方法。

我的问题是:

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

我建议您删除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

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