Skip to content

Instantly share code, notes, and snippets.

@keturn
Last active April 21, 2022 15:21
Show Gist options
  • Save keturn/8bc88525a183fd41c73ffb729b8865be to your computer and use it in GitHub Desktop.
Save keturn/8bc88525a183fd41c73ffb729b8865be to your computer and use it in GitHub Desktop.
test for CursorPagination with floating point field
class FloatingPointCursorPagination(CursorPagination):
__rounding_down = decimal.Context(prec=14, rounding=decimal.ROUND_FLOOR)
__rounding_up = decimal.Context(prec=14, rounding=decimal.ROUND_CEILING)
def _get_position_from_instance(self, instance, ordering):
field_name = ordering[0].lstrip('-')
if isinstance(instance, dict):
attr = instance[field_name]
else:
attr = getattr(instance, field_name)
if isinstance(attr, float):
# repr gives more precision than str
# but we still lost some precision just from the postgresql-to-python translation.
if ordering[0][0] == '-':
attr = self.__rounding_down.create_decimal_from_float(attr)
else:
attr = self.__rounding_up.create_decimal_from_float(attr)
attr_str = force_text(attr)
return attr_str
from django.db import models
from rest_framework import viewsets
from rest_framework.pagination import CursorPagination
class FloatyModel(models.Model):
score = models.FloatField()
class FloatyViewSet(viewsets.ReadOnlyModelViewSet):
queryset = FloatyModel.objects.all().order_by('-score')
pagination_class = CursorPagination
page_size = 3
class TestFloatingPointCursorPagination(APITestCase):
def test_page_boundary_does_not_repeat_elements(self, test_data):
for i in range(12):
FloatyModel.objects.create(score=i/9.0)
viewset_url = 'FIXME'
first_response = self.client.get(viewset_url)
first_page_last_item = first_response.data['results'][-1]
second_response = self.client.get(first_response['next'])
second_page_first_item = second_response.data['results'][0]
self.assertNotEqual(first_page_last_item['pk'], second_page_first_item['pk'])
self.assertGreater(first_page_last_item['score'], second_page_first_item['score'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment