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