Reputation: 129
I am trying to filter data using a decorator action on Django Rest Framework, it works perfect if I use the global queryset (get_queryset() function) but I need to use it in a separate function.
I am using django-filter to perform it. This is the code.
My view:
class ShippingAPI(viewsets.ModelViewSet):
serializer_class = ShippingSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields = ('origin__department', 'destination__department', 'first_collection_date', 'last_collection_date', 'vehicle')
The override (action)
@action(detail=False, methods=['GET'])
def filter_shippings(self, request, **kwargs):
queryset = Shipping.objects.filter(status=2, orderStatus=0)
serializer = SearchShippingSerializer(queryset, many=True) #Yes, I am using another serializer, but it is solved,I use diferent if it is necesary
return Response(serializer.data)
After use my url 'api/filter_shipping/(all filters here)', this still return all the data without the filters I am requesting.
Thanks for your help
Upvotes: 10
Views: 17042
Reputation: 170
I think the filter integration works correctly if you pass the query params along with your action in the URL. Below was the action that I had
@action(methods=['GET'], detail=False)
def export(self, request):
queryset = self.get_queryset()
filtered_queryset = self.filter_queryset(queryset)
When trying to call the export action from DRF browsable API, the request that was getting sent was /api/viewname/export/ instead, it should called like
/api/viewname/export/?query_param_1=value1&?query_param_2=value2
Passing the query params along with the action will call the filterset class and hence you will get a filtered queryset in filtered_queryset variable
Commented on the Github issue as well: https://github.com/carltongibson/django-filter/issues/967#issuecomment-828220562
Upvotes: 10
Reputation: 341
Add filter_queryset function like this. It worked for me. Found the solution in Django-filters issues: https://github.com/carltongibson/django-filter/issues/967 .
@action(detail=False, methods=['GET'])
def filter_shippings(self, request, **kwargs):
queryset = self.filter_queryset(self.get_queryset()).filter(status=2, orderStatus=0)
serializer = SearchShippingSerializer(queryset, many=True) #Yes, I am using another serializer, but it is solved,I use diferent if it is necesary
return Response(serializer.data)
Upvotes: 13
Reputation: 3805
You could override the normal get_queryset
method from the view and check self.action
class ShippingAPI(viewsets.ModelViewSet):
queryset = Shipping.objects.all()
serializer_class = ShippingSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields = ('origin__department', 'destination__department', 'first_collection_date', 'last_collection_date', 'vehicle')
def get_queryset(self):
queryset = super().get_queryset()
if self.action == 'filter_shippings':
queryset = queryset.filter(status=2, orderStatus=0)
elif self.action == 'other_action':
queryset = queryset.filter(...) # other action filter
return queryset
Upvotes: 4
Reputation: 13731
You can filter on the result of get_queryset
to limit your results.
@action(detail=False, methods=['GET'])
def filter_shippings(self, request, **kwargs):
queryset = self.get_queryset().filter(status=2, orderStatus=0)
serializer = SearchShippingSerializer(queryset, many=True) #Yes, I am using another serializer, but it is solved,I use diferent if it is necesary
return Response(serializer.data)
Edit: You can create a custom filter do the filtering as needed. Here is the example from django-filter's docs.
import django_filters
class ProductFilter(django_filters.FilterSet):
class Meta:
model = Product
fields = ['name', 'price', 'manufacturer']
def product_list(request):
filter = ProductFilter(request.GET, queryset=Product.objects.all())
return render(request, 'my_app/template.html', {'filter': filter})
Upvotes: 6