I implemented a modelviewset with django-filter and django default pagination comnbined. Its working fine when I use either django-filter or django pagination. But when they are used simultaneously then I am getting duplicate results in response.
So whats the correct way to use pagination in django-filter with CBV?
class TableMetaView(ModelViewSet):
"""
This will be used to create new tables.
You require to add the table fields in json request and also the job request associated with that
table.
If you want to create new table then pass CREATE NEW TABLE
In response you will get the table list along with the job request for each tables
"""
serializer_class = TableMetaSerializer
queryset = TableMeta.objects.all()
renderer_classes = [JSONRenderer]
filterset_fields = [
"schema_name",
"type",
"status",
"grouping__name",
"dataset__name",
]
ordering_fields = ["created_on", "modified_on"]
ordering = ["-modified_on"]
pagination_class = StandardResultsSetPagination
permission_classes = [
UserHasDatasetChangeAccess & IsTableEditable,
]
def get_queryset(self):
if getattr(self, "swagger_fake_view", False):
# queryset just for schema generation metadata
return TableMeta.objects.none()
return TableMeta.objects.filter(
dataset=get_object_or_404(DataSet, id=self.request.META.get(DATASET_ID, ""))
)
After searching a lot, I managed to do some changes and code is now running fine with django-filters and pagination.
from collections import OrderedDict
from constance import config
from rest_framework.pagination import ( # noqa
CursorPagination,
LimitOffsetPagination,
PageNumberPagination,
)
from rest_framework.response import Response
class MyPagination(PageNumberPagination):
page_size = 5
page_size_query_param = "page_size"
max_page_size = 50
def get_paginated_response(self, data):
return Response(
OrderedDict(
{
"next": self.get_next_link(),
"previous": self.get_previous_link(),
"results": data,
}
)
)
class TableMetaView(ModelViewSet):
"""
This will be used to create new tables.
You require to add the table fields in json request and also the job request associated with that
table.
If you want to create new table then pass CREATE NEW TABLE
In response you will get the table list along with the job request for each tables
"""
serializer_class = TableMetaSerializer
queryset = TableMeta.objects.all()
renderer_classes = [JSONRenderer]
filterset_class = TableFilter
ordering_fields = ["created_on", "modified_on"]
ordering = ["-modified_on"]
pagination_class = MyPagination
permission_classes = [
UserHasDatasetChangeAccess & IsTableEditable,
]
def get_queryset(self):
if getattr(self, "swagger_fake_view", False):
# queryset just for schema generation metadata
return TableMeta.objects.none()
return TableMeta.objects.filter(
dataset=get_object_or_404(DataSet, id=self.request.META.get(DATASET_ID, ""))
)
def list(self, request: Request, *args: Any, **kwargs: Any) -> Response:
filtered_qs = self.filterset_class(request.GET, queryset=self.get_queryset()).qs
page = self.paginate_queryset(queryset=filtered_qs)
serializer = self.serializer_class(page, many=True)
return self.get_paginated_response(serializer.data)
class TableFilter(django_filters.FilterSet):
class Meta:
model = TableMeta
fields = {
"name": ["exact", "icontains"],
"schema_name": ["exact"],
"type": ["exact"],
"status": ["exact"],
"grouping__name": ["exact"],
"dataset__name": ["exact"],
}
Also you need to set default ordering
class TableMeta(models.Model):
class Meta:
ordering = ['-modified_on'] # list of fields here
After this django-filters and pagination are working fine in ModelViewSet.