8

I have been trying to use django-filters but the objects are not getting filtered. Also, the permission is not working for the partial_update views

I have a Viewset which has the basic actions like - list(), retrieve(), destroy(), partial_update() and few other actions, and trying to apply filter for the same.

After some research I found that since I am creating the queryset via filters I will have to override the get_queryset() method. However, that also doesn't seem to be working. Does the filter works only with ModelViewSet or ListApiView?

ViewSet -

class PostViewSet(viewsets.ViewSet):
"""
The Endpoint to list, retrieve, create and delete Posts.

"""
filter_backends = (DjangoFilterBackend, )
# filterset_class = PostFilter
filter_fields = ('pet_age', 'pet_gender', 'breed')

def get_permissions(self):

    if self.action == 'partial_update' or self.action == 'update':
        permission_classes = [IsPostAuthor, ]

    elif self.action == 'create' or self.action == 'destroy':
        permission_classes = [IsAuthenticated, ]

    else:
        permission_classes = [AllowAny, ]

    return[permission() for permission in permission_classes]

def get_queryset(self):
    return Post.objects.active() # This is implemented via custom Manager

def list(self, request, *args, **kwargs):
    """
    Method for Post listing. It can be accessed by anyone.
    """

    serializer = PostListSerializer(self.get_queryset(), many=True, context={"request": request})

    return Response(serializer.data)
# REST CODE TRUNCATED

Permission -

class IsPostAuthor(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
"""

def has_object_permission(self, request, view, obj):
    if request.user.is_authenticated:
        if view.action in ['partial_update', 'update']:
            return obj.user.id == request.user.id
        return False

    return False

PostFilter -

class PostFilter(filters.FilterSet):

class Meta:
    model = Post
    fields = ('pet_age', 'pet_gender', 'breed', )

Manager -

class PostManager(models.Manager):

def active(self):
    return self.filter(post_status='Active')

Any help will be highly appreciated.

5parkp1ug
  • 462
  • 6
  • 17
  • What you mean by "permission is not working"? It seems you didn't add the `IsPostAuthor` to the view – JPG Sep 17 '18 at 11:10
  • I am checking the permission based on the view action, i.e., I want to limit the _partial_update()_ method to be accessed by the user who has created the post (the author). For that I did override the _ get_permissions() _ as mentioned in the [docs](http://www.django-rest-framework.org/api-guide/viewsets/#introspecting-viewset-actions) – 5parkp1ug Sep 17 '18 at 11:18

2 Answers2

13

Okay, So finally found the solution from DRF Docs. The issue was that in case of normal ViewSet you have to override the method filter_queryset() and return the appropriate queryset accordingly. Then use the queryset under filter_queryset as mentioned by Aman -

serializer = PostListSerializer(self.filter_queryset(self.get_queryset()), many=True, context={"request": request})

Below is the code for reference for those who are still facing issues -

filter_queryset -

def filter_queryset(self, queryset):
    filter_backends = (DjangoFilterBackend, )

    # Other condition for different filter backend goes here

    for backend in list(filter_backends):
        queryset = backend().filter_queryset(self.request, queryset, view=self)
    return queryset
5parkp1ug
  • 462
  • 6
  • 17
3

You have overwrite the list method, so it's not working to work call the filter_queryet method.

def list(self, request, *args, **kwargs):
    """
     Method for Post listing. It can be accessed by anyone.
     """

    serializer = PostListSerializer(self.filter_queryset(self.get_queryset()), many=True, context= . 
     {"request": request})

    return Response(serializer.data)
aman kumar
  • 3,086
  • 1
  • 17
  • 24
  • Thanks for the response. However, the method _filter_queryset()_ is implemented under the _PostFilter_ so we can't reference it as _self.filter_queryset()_. Also, i tried overriding this method but that also didn't work. I was thinking if it has to do with ViewSet. Shall i implement the view via _ModelViewSet_ ?? – 5parkp1ug Sep 18 '18 at 09:14
  • https://github.com/encode/django-rest-framework/blob/master/rest_framework/mixins.py, see the ListModelMixin , it's call the self.filter_queryset(self.get_queryset()) – aman kumar Sep 19 '18 at 07:20
  • Yeah but i wasn't using mixin. Anyways the issue is resolved now. Thanks for the inputs though. – 5parkp1ug Sep 19 '18 at 10:56
  • viewsets.ViewSet is class is using that mixin – aman kumar Sep 19 '18 at 15:05