使用Django Rest Framework进行批量和部分更新

12

我希望能够一次性部分更新多个项目。 我已经添加了一个mixin以允许我进行批量创建(并且运作良好),但即使我添加了一个参数,它也不允许对列表进行patch操作。

我猜这是一个路由问题。 我需要一个新的视图来处理/上的PATCH请求(而不是/id/),但我已经超出了我的能力范围。

针对此问题的现有答案在3.8中无效,至少对我没有用。 我需要对以下内容做什么?

class ResourceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Resource
        fields = ('id', 'name', ...)
        read_only_fields = ('id',)

 class BulkMixin:
     def get_serializer(self, *args, **kwargs):
        if isinstance(kwargs.get('data', {}), list):
            kwargs['many'] = True
            kwargs['partial'] = True

        return super().get_serializer(*args, **kwargs)

class ResourceViewSet(BulkMixin, viewsets.ModelViewSet):
    serializer_class = ResourceSerializer
2个回答

11

在这个问题上,我已经折腾了大约10个小时,最终我决定放弃“正确的方法”,而转向“能用的hack方法”。我在我的视图集中添加了以下代码。

from rest_framework.decorators import action

@action(methods=['patch'], detail=False)
def bulk_update(self, request):

    data = {  # we need to separate out the id from the data
        i['id']: {k: v for k, v in i.items() if k != 'id'}
        for i in request.data
    }

    for inst in self.get_queryset().filter(id__in=data.keys()):
        serializer = self.get_serializer(inst, data=data[inst.id], partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()

    return Response({})

如果我补丁一个列表[{id: 123, otherfield: "abc"}, ...],现在这将进行批量部分更新。我相当确定这是做n+1个查询,而在原始ORM中效率会更高...但现在,它比n次请求要好得多。此外,如果ID不在查询集中,它将跳过而不是出错。这对我有用,但可能不适用于其他人。

我会在48小时内在这个问题上放置赏金,以吸引一些好答案。


1
我建议不要自己尝试实现这个。考虑使用django-rest-framework-bulk。它支持批量、部分更新,并提供序列化器、视图和路由器,使设置变得非常简单。

1
我尝试过了,但在现代DRF中无法运行(即:我无法让它工作)。这个项目已经被放弃了。作者曾经评论说他们可能会重新开始维护,但是谁知道呢。 - Oli
我个人在现代DRF中使用过它。如果你无法让许多其他人都能使用的第三方库正常工作,那么我不认为你会尝试重复造轮子会有什么成功。至少在排除它之前,尝试弄清楚为什么它不起作用。 - Levi Payne
1
不能信任一个六年前的项目,而DRF本身正在不断发展。 - Cedric Druck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接