restless icon indicating copy to clipboard operation
restless copied to clipboard

Support pagination natively

Open seocam opened this issue 8 years ago • 8 comments

What do you guys think about native support to pagination? We could implement that using Django paginator (for example) since it doesn't have external dependencies.

That's helpful in most listing APIs. Here is just an example on how it could be implemented in the Resource:

    DEFAULT_RESULTS_PER_PAGE = 20

class Resource(object):

   ...

    def serialize_list(self, data):
        if getattr(self, 'paginate', False):
            page_size = getattr(self, 'page_size', DEFAULT_RESULTS_PER_PAGE)
            paginator = Paginator(data, page_size)

            try:
                page_number = int(self.request.GET.get('p', 1))
            except ValueError:
                page_number = None

            if page_number not in paginator.page_range:
                raise BadRequest('Invalid page number')

            self.page = paginator.page(page_number)
            data = self.page.object_list

        return super().serialize_list(data)

    def wrap_list_response(self, data):
        response_dict = super().wrap_list_response(data)

        if hasattr(self, 'page'):
            if self.page.has_next():
                next_page = self.page.next_page_number()
            else:
                next_page = None

            if self.page.has_previous():
                previous_page = self.page.previous_page_number()
            else:
                previous_page = None

            response_dict['pagination'] = {
                'num_pages': self.page.paginator.num_pages,
                'count': self.page.paginator.count,
                'page': self.page.number,
                'start_index': self.page.start_index(),
                'end_index': self.page.end_index(),
                'next_page': next_page,
                'previous_page': previous_page,
            }

        return response_dict

And to use simply add to your resource:

MyResource(Resource):
    paginate = True
    page_size = 50  # optional

If that seems useful I'm willing to create a PR with tests and docs.

seocam avatar May 23 '16 19:05 seocam

I think it's better to write your own paginate mixin. Restless is not Django-only and it could be tricky to support pagination for every usage.

toxinu avatar Jun 10 '16 14:06 toxinu

@seocam nice approach, just a note: there's not need to use

        try:
            page_number = int(self.request.GET.get('p', 1))
        except ValueError:
            page_number = None

        if page_number not in paginator.page_range:
            raise BadRequest('Invalid page number')

since the django Paginator class will take care of bad page numbers, so your code can be even shorter:

def serialize_list(self, data):
    if getattr(self, 'paginate', False):
        page_size = getattr(self, 'page_size', DEFAULT_RESULTS_PER_PAGE)
        paginator = Paginator(data, page_size)
        page_number = self.request.GET.get('p', 1)
        self.page = paginator.page(page_number)  #  This django method takes care of the page number
        data = self.page.object_list

    return super().serialize_list(data)

https://github.com/django/django/blob/master/django/core/paginator.py#L52

ghost avatar Feb 26 '17 08:02 ghost

Just add a little note:

def serialize_list(self, data):
    if getattr(self, 'paginate', False):
        page_size = getattr(self, 'page_size', DEFAULT_RESULTS_PER_PAGE)
        paginator = Paginator(data.value, page_size) # get value data
        page_number = self.request.GET.get('p', 1)
        self.page = paginator.page(page_number)  #  This django method takes care of the page number
        data = self.page.object_list

    return super().serialize_list(data)

https://docs.djangoproject.com/en/1.10/topics/pagination/#example

If you got error *** TypeError: object of type 'Data' has no len() that my snippet code fix that error

repodevs avatar Apr 17 '17 10:04 repodevs

@seocam just wondering if you had any plans on submitting a PR for this feature? Thanks!

CalebeGeazi avatar Sep 04 '18 16:09 CalebeGeazi

Hey @CalebeGeazi. Honestly I had forgot that this issue was open. Thanks for bumping it up.

@toastdriven do you have any thoughts about that? If you don't oppose I think it's time to add a few extra features here ;)

seocam avatar Sep 04 '18 16:09 seocam

I've merged #114 witch adds pagination for Django. @Marcelo-Theodoro could you create a new PR that actually adds the pagination independent of framework?

Thanks!

seocam avatar Jan 15 '19 20:01 seocam

Guys, do you think that the pagination should be enabled or disabled by default?

Marcelo-Theodoro avatar Jan 16 '19 13:01 Marcelo-Theodoro

Guys, do you think that the pagination should be enabled or disabled by default?

I think we could turn it on or off depending on the per_page class attribute. If it getattr(resource, 'per_page') evaluates to True, pagination is enabled, if it evaluates do False, it's disabled.

cuducos avatar Feb 05 '19 15:02 cuducos