Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support pagination natively #78

Open
seocam opened this issue May 23, 2016 · 8 comments
Open

Support pagination natively #78

seocam opened this issue May 23, 2016 · 8 comments
Assignees

Comments

@seocam
Copy link
Collaborator

seocam commented May 23, 2016

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.

@toxinu
Copy link
Contributor

toxinu commented Jun 10, 2016

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.

@ghost
Copy link

ghost commented Feb 26, 2017

@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

@repodevs
Copy link

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

@seocam seocam self-assigned this May 22, 2017
@CalebeGeazi
Copy link

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

@seocam
Copy link
Collaborator Author

seocam commented Sep 4, 2018

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
Copy link
Collaborator Author

seocam commented Jan 15, 2019

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!

@Marcelo-Theodoro
Copy link
Contributor

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

@cuducos
Copy link

cuducos commented Feb 5, 2019

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants