Entrée

Sometimes we need to map some url parameters to different model fields, due to some restrictions or for backward compability.

Let’s say we’d like to show/filter “customer” instead of “user” in our DRF API.

# httpie
$ http ":8000/authors?customer=3"
# or with curl
# $ curl http://localhost:8000/authors?customer=3

[
    {
        "first_name": "Name3",
        "full_name": "Name3 Surname3",
        "id": 3,
        "last_name": "Surname3",
        "customer": 3
    }
]

Initial Code

For this purpose I will use our Django REST Framework example github repo. You can find updated code on the branch map-filter-params.

Let’s use our basic ArticleViewSet shown below:

# src/articles/views.py
class ArticleViewSet(viewsets.ModelViewSet):
    serializer_class = ArticleSerializer
    queryset = Article.objects.all()
    filter_backends = (
        DjangoFilterBackend,
        OrderingFilter,
        SearchFilter,
    )
    filterset_fields = ("id", "title", "regions", "regions__code")
    search_fields = ("id", "title", "regions__name", "regions__code")
    ordering_fields = ("title",)
    ordering = "title"

In this view, as you may see, we filter with id, title, regions, regions__code.

Custom FilterSet

Mapping a filter field to different model field is quite simple: just provide field_name param to related filter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# src/articles/filters.py
from django_filters import rest_framework as filters

from src.articles.models import Article


class ArticleFilterSet(filters.FilterSet):
    subject = filters.CharFilter(field_name="title", lookup_expr="exact")

    class Meta:
        model = Article
        fields = ("id", "subject", "regions", "regions__code")

Then you can use this custom FilterSet in the view like below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class ArticleViewSet(viewsets.ModelViewSet):
    serializer_class = ArticleSerializer
    queryset = Article.objects.all()
    filter_backends = (
        DjangoFilterBackend,
        OrderingFilter,
        SearchFilter,
    )
    filterset_class = ArticleFilterSet
    search_fields = ("id", "title", "regions__name", "regions__code")
    ordering_fields = ("title",)
    ordering = "title"

All done!