Reputation: 33
Have the next Django REST question.
I have the view.
class MessageViewSet(viewsets.ModelViewSet):
serializer_class = MessageSerializer
queryset = Message.objects.filter(isread = False)
def mark_read():
queryset = Message.objects.update(isread=True)
return Response({'read':queryset})
And router in urls.py
router = SimpleRouter() router.register(r'api/get_messages', MessageViewSet)
urlpatterns = [
url(r'^$', MainView.as_view(), name='main'),
url(r'^', include(router.urls)) ]
Now i have 'get_messages' page which shows all list.
How can i implement a method which would change 'isread' value of model instanse from False to True, when I visit a 'mark_read' page? As you can see, i tried to write method in the class. But when i'm trying to call it in urls in this way:
router.register(r'api/mark_read', MessageViewSet.mark_read),
Here comes an error.
assert queryset is not None, '
base_name
argument not specified, and could ' \ AssertionError:base_name
argument not specified, and could not automatically determine the name from the viewset, as it does not have a.queryset
attribute.
Maybe i shouldnt use router, and rewrite view and urls in other way. If u know how to solve this problem, please answer. Thanks.
Upvotes: 3
Views: 151
Reputation: 33
Thanks to @ivan-semochkin and @Shaumux for replies. Advices were really helpful.
That is my route. I used detail_route instead of list_route.
@detail_route(methods=['get','put'], url_name='mark_read/')
def mark_read(self, request, pk=None):
queryset = Message.objects.filter(pk=pk).update(isread=True)
return Response({'read':queryset})
Now 'isread' value is changing wnen i visit 'mark_read' page. Link: "api/get_messages/pk/mark_read"
Does anyone know, is it posslible to make links looking the next way: "api/get_messages" - list, "api/mark_read/pk" - changing isread value.
Is it possible to create something like this? "api/mark_read?=pk"
Upvotes: 0
Reputation: 745
Since you are using a model viewset you can directly use put or patch rest method to send the desired value for the desired field as the data. Ideally in rest get should not change model values. If you really want a different end point put the list_route or detail_route decorator on your mark_read method, and make them a valid call for only a put and/or patch call
from rest_framework.decorators import list_route
class MessageViewSet(viewsets.ModelViewSet):
@list_route(methods=['Patch', 'PUT'])
def mark_read(self, request):
queryset = Message.objects.update(isread=True)
return Response({'read':queryset})
Upvotes: 2
Reputation: 8897
You can use detail_route
or list_route
decorators.
from rest_framework.decorators import list_route
class MessageViewSet(viewsets.ModelViewSet):
@list_route()
def mark_read(self, request):
queryset = Message.objects.update(isread=True)
return Response({'read':queryset})
With that mark_read
method will be available at api/get_messages/mark_read
. And you don't need to create separate router, just use one you created for MessageViewSet
Upvotes: 2