4

I have to Models: A Library can have many Books.

Right now I have a URL for performing CRUD on Books in a specific Library:

router.register(r'books/(?P<library_id>[0-9]+)', BookViewSet, base_name='books')

and corresponding view:

class BookViewSet(viewsets.ModelViewSet):

    serializer_class = BookSerializer
    def get_queryset(self):

        genre_query = self.request.query_params.get('genre', None)
        status_query = self.request.query_params.get('status', None)
        author_query = self.request.query_params.get('author', None)

        books = Book.objects.filter(which_library=self.kwargs.get('library_id'))
        if genre_query:
            books = books.filter(genre=genre_query)
        if status_query:
            books = books.filter(status=status_query)
        if author_query:
            books = books.filter(author=author_query)
        return books 

I originally did not use ModelViewSet instead I had functions with @api_view decorators, one of which was following (returning books added in last two weeks, I had a separate URL for this function as api/books//new_arrivals):

@api_view(['GET'])
def new_arrivals(request, library_id):
    """
    List all new arrival books in a specific library
    """
    d=timezone.now()-timedelta(days=14)
    if request.method == 'GET':
        books = Book.objects.filter(which_library=library_id)
        books = books.filter(when_added__gte=d)
        serializer = BookSerializer(books, many=True)
        return Response(serializer.data)

While using ModelViewSets, how can I do it? Must I add another URL and then write another class for new_arrivals or write a function in existing BookViewSet? How to achieve handling those two GET methods in that case?

2 Answers 2

2

You can extend traditional viewSet by adding special methods list_route and detail_route. With this decorators you can add new urls produced by ViewSet. In this case list_route is more suitable:

from rest_framework.decorators import list_route

class BookViewSet(viewsets.ModelViewSet):
    ...
    @list_route()
    def new_arrivals(self, request):
        books = self.get_queryset()
        d=timezone.now()-timedelta(days=14)
        books = books.filter(when_added__gte=d 
        serializer = self.get_serializer(books, many=True)
        return Response(serializer.data)

This will add additional url to the viewSet: books/{library_id}/new_arrivals.

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

1 Comment

Thanks lot once again! Now I have a complete working example of all different possibilities with ModelViewSet :)
1

list_route and detail_route are depreciated and they are merged with decorator action.

https://www.django-rest-framework.org/community/3.8-announcement/#deprecations

Comments

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.