Mixins, Filtering & Pagination
AnimalViewSet sets two attributes, and ReadOnlyModelViewSet provides the rest. We change what it does by overriding its methods, and with DRF's settings.
A Viewset Is Its Mixins
Like Django's generic views, ReadOnlyModelViewSet is built from mixins. Two DRF mixins give it the list and retrieve actions. A request whose method has no action gets 405 Method Not Allowed, so a POST to animals/ is refused.
DRF provides mixins for listing, creating, retrieving, updating, and deleting model rows. Its router documentation lists each action's HTTP method and URL.
ModelViewSet has all five mixins. A viewset can use any of them, such as CreateModelMixin alone for an endpoint that only accepts new rows.
An endpoint other than a model's list or detail doesn't need a viewset. It can be a function with DRF's @api_view decorator. It still behaves like the rest of the API, with content negotiation, the browsable API, and DRF's settings.
DRF's documentation covers function-based views. For a route beyond a viewset's regular actions, the @action decorator turns a method into an extra action.
Filtering the List
The API needs the list page's species filter, supplied as ?species=rabbit in the query string.
A viewset narrows its rows for a request in get_queryset(), as ListView does. The override calls super().get_queryset() to get the class's queryset, then narrows it.
DRF's request holds the query string's values in request.query_params, its name for Django's request.GET.
Paginating the List
Our list returns every animal in one response, and a rescue can have hundreds of animals. The list page splits them into pages, and the API's list needs to as well.
DRF's settings go in one Django setting, REST_FRAMEWORK, a dictionary in config/settings.py. Two of them paginate a viewset's list:
DEFAULT_PAGINATION_CLASS: The class that splits the list, named by its import path as a string, such as"rest_framework.pagination.PageNumberPagination".PAGE_SIZE: The rows on each page.
Both are None by default, so a list comes back whole.
With PageNumberPagination, the list's response is an object with these keys:
count: The total number of rows.nextandprevious: Links to the next and previous pages.results: The rows on this page.
A client requests another page with ?page=2, the same parameter our list page uses.
Info
Production APIs often turn off the browsable API by adding DEFAULT_RENDERER_CLASSES to REST_FRAMEWORK and listing only rest_framework.renderers.JSONRenderer.
Linking Each Animal
A client reading the list needs each animal's URL. If it builds that URL from the id, it has to know our URL layout.
"url" in a ModelSerializer's fields becomes a link to each row's endpoint. DRF builds the link from the router's animal-detail route, so the client can follow it.
In the exercise, we'll filter the list by species, paginate it, and add "url" to AnimalSerializer's fields.