Search code examples
pythondjangopaginationelasticsearch-dsl

Python elasticsearch-dsl django pagination


How can i use django pagination on elasticsearch dsl. My code:

query = MultiMatch(query=q, fields=['title', 'body'], fuzziness='AUTO')

s = Search(using=elastic_client, index='post').query(query).sort('-created_at')
response = s.execute()

// this always returns page count 1
paginator = Paginator(response, 100)
page = request.GET.get('page')
try:
    posts = paginator.page(page)
except PageNotAnInteger:
    posts = paginator.page(1)
except EmptyPage:
    posts = paginator.page(paginator.num_pages)

Any solution for this?


Solution

  • I found this paginator on this link:

    from django.core.paginator import Paginator, Page
    
    class DSEPaginator(Paginator):
        """
        Override Django's built-in Paginator class to take in a count/total number of items;
        Elasticsearch provides the total as a part of the query results, so we can minimize hits.
        """
        def __init__(self, *args, **kwargs):
            super(DSEPaginator, self).__init__(*args, **kwargs)
            self._count = self.object_list.hits.total
    
        def page(self, number):
            # this is overridden to prevent any slicing of the object_list - Elasticsearch has
            # returned the sliced data already.
            number = self.validate_number(number)
            return Page(self.object_list, number, self)
    

    and then in view i use:

        q = request.GET.get('q', None)
        page = int(request.GET.get('page', '1'))
        start = (page-1) * 10
        end = start + 10
    
        query = MultiMatch(query=q, fields=['title', 'body'], fuzziness='AUTO')
        s = Search(using=elastic_client, index='post').query(query)[start:end]
        response = s.execute()
    
        paginator = DSEPaginator(response, settings.POSTS_PER_PAGE)
        try:
            posts = paginator.page(page)
        except PageNotAnInteger:
            posts = paginator.page(1)
        except EmptyPage:
            posts = paginator.page(paginator.num_pages)
    

    this way it works perfectly..