Search code examples
pythondjangodjango-rest-frameworkbootstrap-table

How to make DRF ordering and filtering work with custom query_params that generated by bootstrap-table extension


I have working version without api, filling table with loop in templates. Works as i need, but because there is thousands rows of data, page loading 5-20 seconds. So i want use server side pagination. Problem is - bootstrap-table script generates url like this for example:

/api/parcels/?search=&sort=Size&order=desc&offset=0&limit=25&multiSort[0][sortName]=Price&multiSort[0][sortOrder]=asc&multiSort[1][sortName]=Region&multiSort[1][sortOrder]=asc

bootstrap-table.js can sort by single column, also have extension for multiple column sort, and own pagination.

Probably best way is to rewrite JS more into format of DRF. But i want do it opposite way, at least to get more experience with DRF.

So, i know DRF have own ordering accodring docs:

http://example.com/api/users?ordering=account,username

ordering_fields = ['account', 'username']

and with ORDERING_PARAM you can change name for query param. But format offered by bootstrap-table.js not fits at all. So question is - is there a way to change DRF ordering according to my needs and which is better way?

Just in case, my view and serializer so far.

class ParcelViewSet(generics.ListAPIView):
serializer_class = ParcelSerializer

def get_queryset(self):
    queryset = Parcels.objects.all()
    return queryset

def list(self, request, *args, **kwargs):
    queryset = self.get_queryset()
    serializer = self.get_serializer(queryset, many=True)

    response_data = {
        "total": len(serializer.data),
        "totalNotFiltered": len(serializer.data),
        'rows': serializer.data
    }
    return Response(response_data)


class ParcelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Parcels
        fields = '__all__'

Solution

  • This way it works for me just fine. First check if there is sort param, so we make sure if user sorting by single or multiple columns.

    Now need to figure out same for pagination :)

    class CustomOrderFilter(OrderingFilter):
    
    def get_ordering(self, request, queryset, view):
        sort = request.query_params.get('sort')
        if sort:
            order = request.query_params.get('order')
            ordering = ['-'+sort if order == 'desc' else sort]
            return ordering
    
        order_fields_bt = [v for k, v in request.query_params.items() if 'sortName' in k]
        if order_fields_bt:
            order_direction_bt = [v for k, v in request.query_params.items() if 'sortOrder' in k]
            ordering = [''+order_fields_bt[i] if d == 'asc' else '-'+order_fields_bt[i] for i, d in enumerate(order_direction_bt)]
            return ordering
    
        # No ordering was included, or all the ordering fields were invalid
        return self.get_default_ordering(view)