I have a Django app for contests where a contest can have multiple entries -
Contest
in models.py
class Contest(models.Model):
is_winners_announced = models.BooleanField(default=False)
...
ContestEntry
in models.py
class ContestEntry(models.Model):
contest = models.ForeignKey(Contest, on_delete=models.CASCADE,
related_name='entries')
submitted_at = models.DateTimeField(auto_now_add=True)
assigned_rank = models.PositiveSmallIntegerField(null=True, blank=True)
...
In the ContestViewSet, I have a detail
route which serves all the entries for a contest -
def pagination_type_by_field(PaginationClass, field):
class CustomPaginationClass(PaginationClass):
ordering = field
return CustomPaginationClass
...
@decorators.action(
detail=True,
methods=['GET'],
)
def entries(self, request, pk=None):
contest = self.get_object()
entries = contest.entries.all()
# Order by rank only if winners are announced
ordering_array = ['-submitted_at']
if contest.is_winners_announced:
ordering_array.insert(0, 'assigned_rank')
pagination_obj = pagination_type_by_field(
pagination.CursorPagination, ordering_array)()
paginated_data = contest_serializers.ContestEntrySerializer(
instance=pagination_obj.paginate_queryset(entries, request),
many=True,
context={'request': request},
).data
return pagination_obj.get_paginated_response(paginated_data)
Pagination works fine when winners are not declared for a contest -
GET http://localhost:8000/contests/<id>/entries/
{
"next": "http://localhost:8000/contests/<id>/entries/?cursor=cD0yMDIwLTAyLTE3KzIwJTNBNDQlM0EwNy4yMDMyMTUlMkIwMCUzQTAw",
"previous": null,
"results": [ // Contains all objects and pagination works
{...},
...
]
}
But when the winners are announced, pagination breaks:
GET http://localhost:8000/contests/<id>/entries/
{
"next": "https://localhost:8000/contests/4/entries/?cursor=bz03JnA9Mw%3D%3D",
"previous": null,
"results": [ // Contains all objects only for the first page; next page is empty even when there are more entries pending to be displayed
{...},
...
]
}
The strange thing I see here is that cursor in the second case looks different from what it normally looks like.