I am trying to add update options to the list items. So that if anyone perform 'PATCH' request to it I will get the details and update them. This is my code for the implementation
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!'})
But here the request to the api is only accepting GET, HEAD and OPTIONS. I even tried adding http_method_names = ('get', 'patch')
but even this is not working!!
Is there any way to put the patch request to the view ?
Thanks
Here is my implementation, 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
If you're not using DRF routers (because when doing anything "custom" like this, using only naked views is usually much more pain-free), edit urls.py like so:
urlpatterns = [
...
re_path(
r'^path/to/mymodels',
MyListView.as_view({
'get': 'list',
'patch': 'list_update', # <--
}),
),
]
If using routers, this little hack works and is simple, but not terribly nice:
router = routers.DefaultRouter(trailing_slash=False)
router.routes[0].mapping['patch'] = 'list_update' # <--
...
It might also makes sense to override get_serializer_class
on the viewset to have a different serializer for list_update action.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With