1

I have a model with a Boolean field, and I want to paginate the query set of this model by the Boolean field with the rule:

  1. Page size is 10
  2. Each page contain 2 items whose Boolean field is True and 8 items whose Boolean field is False
  3. If one page can not satisfy rule 2, such as there are remaining items with False value after pagination, just append them to page

For example:

With the Food model, I want every page has 2 fat food and 8 non-fat food

class Food(models.Model):
    # whether fat food 
    is_fat_food = models.BooleanField(default=False)
    # other field

Now, I implement the pagination with the following algorithm in get_queryset. BTW, I use ListModelMixin in my interface to implement pagination.

def get_queryset(self):
    fat_food_qs = Food.objects.filter(is_fat_food=True)
    non_fat_food_qs = Food.objects.filter(is_fat_food=False)
    final_qs = []
    fat_page_size = 2
    no_fat_page_size = 8
    i = 0
    j = 0
    while i < len(fat_food_qs) and j < len(non_fat_food_qs):
        if i + fat_page_size > len(fat_food_qs):
            break
        if j + no_fat_page_size > len(non_fat_food_qs):
            break
        final_qs += fat_food_qs[i:i+fat_page_size]
        final_qs += non_fat_food_qs[j:j+non_fat_food_qs]
        i += fat_page_size
        j += non_fat_food_qs
    # remaining food no need to obey the rule, just append
    if i < len(fat_food_qs):
        final_qs += fat_food_qs[i:]
    if j < len(non_fat_food_qs):
        final_qs += non_fat_food_qs[j:]
    return final_qs

By this algorithm, I get the right and expected result, but I think it is not efficient.

Because default pagination algorithm based on query set use lazy-loading mechanism which just load one specific page when request that page.

But in my algorithm, I need to traverse and handle the query set before pagination.

I am a freshman in django and I don't know whether I need to implement a pagination without using ListModelMixin, just based on the request parameter page and page_size to get the specific page query result and construct the prev and next page link in response.

Any suggestions will be greatly appreciated.

PS: I am also a freshman in python, If any codes are not pythonic, please let me know, thanks.

Fogmoon
  • 569
  • 5
  • 16

1 Answers1

3

There is a paginator available in django core.

from django.core.paginator import Paginator
import itertools

page_size1 = 2
page_size2 = 8
queryset_obj1 = Food.objects.filter(is_fat_food=True)
queryset_obj2 = Food.objects.filter(is_fat_food=False)

data1 = Paginator(queryset_obj1, page_size).page(page_number).object_list 
data2 = Paginator(queryset_obj2, page_size).page(page_number).object_list     
merged = list(itertool.chain(data1, data2))  # merged is a list containing Food objects.

The solution above won't be much optimum than provided in answer for very less db rows but it would perform better for large data.

Arpit Solanki
  • 9,567
  • 3
  • 41
  • 57
  • Thanks for your answer, I know `paginator`. In my opinion, standard `paginator` can not implement my requirement. – Fogmoon Jun 23 '17 at 13:11
  • You should read my question more carefully. I want to implement pagination based on `model field` more efficiently. Now I implemented `get_queryset` method is based on `paginator`. The point is the query set can not be easily given by `model.objects.all()`. – Fogmoon Jun 23 '17 at 13:23
  • see the edit this would be more maintainable solution without using much heuristics – Arpit Solanki Jun 23 '17 at 13:33
  • Thanks again. This solution is good. Frankly I think about it before. But two query set may do not have same pages. In this case, the query set with more pages need fill the full page. Also it is not easy to construct the `next` and `prev` page link. – Fogmoon Jun 23 '17 at 13:41
  • The queryset will always have same page your solution and solution above will provide same result always and that is for sure, data is always indexed and filter will always give results in same order. – Arpit Solanki Jun 23 '17 at 13:44
  • Do you think about `4 fat food` with `80 non-fat food`? – Fogmoon Jun 23 '17 at 14:00
  • it will give null for fat food after 2 pages. But that's the rest designs. In this case what output do you expect – Arpit Solanki Jun 23 '17 at 14:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/147468/discussion-between-fogmoon-and-arpit-solanki). – Fogmoon Jun 23 '17 at 14:09