class PaginationMixin(object):
    """
    Get the paginate_by value from either (in order of priority):
    - the querystring
    - the session
    - the User's profile in the database
    - the default value

    Limit the chosen paginate_by value to avoid abuse (for example,
    setting it to 0 makes Django return all the items).
    Save the value in the session so that the User doesn't have to specity it.
    """
    DEFAULT_PAGE_SIZE = 10
    MIN_PAGE_SIZE = 1
    MAX_PAGE_SIZE = 50

    def get_paginate_by(self, queryset):
        # Get the page_size value
        page_size = (int(self.request.GET.get('page_size', 0)) or
                     self.request.session.get('page_size') or
                     self.request.user.profile.page_size or
                     self.DEFAULT_PAGE_SIZE)

        # Limit the page_size to lie between the set range
        if page_size < self.MIN_PAGE_SIZE or page_size > self.MAX_PAGE_SIZE:
            page_size = self.DEFAULT_PAGE_SIZE

        # Save the page_size in the session
        self.request.session['page_size'] = page_size
        # Save the page_size in the User's Profile model, but only if it changed.
        if page_size != self.request.user.profile.page_size:
            self.request.user.profile.page_size = page_size
            self.request.user.profile.save()

        # Return the page_size
        return page_size