Skip to content

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.
  • next and previous: 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.