3

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.

2
  • 1
    Use ListView as you'll also need add more filter like users etc. And update that using same query. And do this in queryset itself. And return it. Instead accessing function of view. Commented Jan 30, 2018 at 11:12
  • I think that for another model it's suitable to use ViewSet too. ListView good for deep customizing though. Thank you for response! Commented Jan 30, 2018 at 18:24

3 Answers 3

2

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

docs reference

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for response. For those who will visit this page later - see my answer below covering my special case.
2

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})

Comments

0

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"

1 Comment

You can create a custom router inheriting from SimpleRouter or just create a plain urls.py route

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.