Filtering querysets in Django Rest Framework

Viewed 3662

Today i have a really strange behoviour. I have added a custom mixin to my User Viewset to filter the users by username and password and other fields. the code look like the following:

class MultipleFieldLookupMixin(object):
    """
    Apply this mixin to any view or viewset to get multiple field filtering
    based on a `lookup_fields` attribute, instead of the default single field filtering.
    """
    def get_object(self):
        queryset = self.get_queryset()             # Get the base queryset
        queryset = self.filter_queryset(queryset)  # Apply any filter backends
        filter = {}
        for field in self.lookup_fields:
            if field in self.kwargs.keys(): # Ignore empty fields.
                filter[field] = self.kwargs[field]
        obj = get_object_or_404(queryset, **filter)  # Lookup the object
        return obj


class UserView(MultipleFieldLookupMixin, viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    lookup_fields = ['username', 'pwd', 'token_confirm', 'email', 'token_cng_pwd']

i would like the list operation to filter the queryset in every given parameter (so None if none is avalable and all if all are available).

But the list endpoint continues to show every user to me, without filtering them.

Where am i wrong? Do i have to manually set a filterbackend? am I doing some stupid mistake? Thanks a lot

Maybe do i have to put those parameters inside the urls.py?

I have changed the urls.py not but it throws me an exception:

router.register('user', views.UserView)
router.register('user/username/{username}/', views.UserView, username = 'username')
router.register('user/username/{username}/pwd/{pwd}/', views.UserView, username = 'username', pwd = 'pwd')
router.register('user/email/{email}/', views.Userview, email = 'email')
router.register('user/token_confirm/{token_confirm}/', views.UserView, token_confirm = 'token_confirm')
router.register('user/token_cng_pwd/{token_cng_pwd}/', views.UserView, token_cng_pwd = 'token_cng_pwd')

Exception:

router.register('user/username/{username}', views.UserView, username = 'username')
TypeError: register() got an unexpected keyword argument 'username'

I didn't mean to filter the query but i'll give a try!

1 Answers

The get_object return a single object instance. the docstring say you can look for single object with one or more fields (attributes).

obj = get_object_or_404(queryset, **filter)

to filter list use django_filters it build exactly for this purpose, it is very powerful and easy to use.

from rest_framework import routers, serializers, viewsets
from rest_framework import filters
import django_filters.rest_framework
from .serializer import UserSerializer, User



class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = [django_filters.rest_framework.DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ['username' , 'first_name']
    search_fields = ['username']
    ordering_fields = ['username']
    ordering = ['username']

If your still curious or want to build a custom filtering for list view, then override the get_queryset() method of the viewset.

Related