Django Rest框架列表更新API视图

时间:2018-11-10 06:48:54

标签: django django-rest-framework

我正在尝试将更新选项添加​​到列表项。这样,如果有人执行“ PATCH”请求,我将获取详细信息并进行更新。这是我的实现代码

class SwitchListView(UpdateModelMixin, ListAPIView):
  serializer_class = serializers.SwitchSerializer
  lookup_field = 'home_id'

  def get_queryset(self):
    home_id = self.kwargs.get('home_id', None)
    if home_id is None or int(home_id) < 0 or \
            self.request.user.pk != models.Home.objects.filter(pk=home_id)[0].user.pk:
        return models.Switch.objects.none()
    query = models.Switch.objects.filter(home=models.Home.objects.filter(pk=home_id))
    return query

  def get(self, request, *args, **kwargs):
    return super(SwitchListView, self).get(request, *args, **kwargs)

  def partial_update(self, request, *args, **kwargs):
    print("Came here")
    data = request.data['data']
    for i in data:
        query = self.get_queryset().filter(i['pk'])
        if query.exists():
            query.switch_status = i['switch_status']
            query.save()

    return Response({'message': 'successfully updated switch!'})

但是在这里,对api的请求仅接受GET,HEAD和OPTIONS。我什至尝试添加http_method_names = ('get', 'patch'),但即使这样也不起作用!

有什么办法可以将补丁请求发送到视图?

谢谢

3 个答案:

答案 0 :(得分:0)

from rest_framework.decorators import detail_route

...

@detail_route(methods=['put', 'patch'])
def partial_update(self, request, *args, **kwargs):
    ...

尝试吗?

答案 1 :(得分:0)

这是我的实现,FWIW:

from rest_framework import viewsets
from rest_framework.response import Response

class MyListView(viewsets.mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = ...
    queryset = MyModel.objects.all()

    def list_update(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        instances = list(queryset)
        count = len(instances)
        # TODO perhaps validate for max allowed count, before doing list(queryset) !
        data = [request.data] * count
        serializer = self.get_serializer(
            instances, data, many=True, partial=True)
        serializer.is_valid(raise_exception=True)
        self.perform_list_update(serializer)
        return Response(status=204)

    def perform_list_update(self, serializer):
        for instance, data in zip(
                serializer.instance, serializer.validated_data):
            for attr, value in data.items():
                setattr(instance, attr, value)
            instance.save()
        # alternatively use a queryset.update, but be aware that it will not
        # fire pre_save and post_save signals

如果您不使用DRF路由器(因为它们很烂),请像这样编辑urls.py:

urlpatterns = [
    ...
    re_path(
        r'^path/to/mymodels',
        MyListView.as_view({
            'get': 'list', 
            'patch': 'list_update',  # <--
        }),
    ),
]

如果使用路由器,这个小技巧很简单,但效果并不好:

router = routers.DefaultRouter(trailing_slash=False)
router.routes[0].mapping['patch'] = 'list_update'  # <--
...

在视图集上覆盖get_serializer_class以使list_update操作具有不同的序列化器也可能是有意义的。

答案 2 :(得分:0)

我的版本基于 frnhr,但不想使用 GenericViewSet。我还尝试使用 putpatch 使其更符合现有的通用视图,这样我就不需要弄乱路由器了。

class FooBulkUpdateAPIView(ListAPIView):
    queryset = Foo.objects.all()
    serializer_class = FooBulkUpdateSerializer

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def patch(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instances = self.filter_queryset(self.get_queryset())
        data = [request.data] * instances.count()
        serializer = self.get_serializer(instances, data, many=True, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        return Response(status=204)

    def perform_update(self, serializer):
        for instance, data in zip(serializer.instance, serializer.validated_data):
            for attr, value in data.items():
                setattr(instance, attr, value)
            instance.save()