我正在尝试将更新选项添加到列表项。这样,如果有人执行“ 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')
,但即使这样也不起作用!
有什么办法可以将补丁请求发送到视图?
谢谢
答案 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
。我还尝试使用 put
和 patch
使其更符合现有的通用视图,这样我就不需要弄乱路由器了。
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()