old_contents: # Copyright (c) 2015 Ansible, Inc.
  # All Rights Reserved.
  
  # Django REST Framework
  from django.conf import settings
  from rest_framework import pagination
  from rest_framework.utils.urls import replace_query_param
  
  
  class Pagination(pagination.PageNumberPagination):
  
      page_size_query_param = 'page_size'
      max_page_size = settings.MAX_PAGE_SIZE
  
      def get_next_link(self):
          if not self.page.has_next():
              return None
          url = self.request and self.request.get_full_path() or ''
          url = url.encode('utf-8')
          page_number = self.page.next_page_number()
          return replace_query_param(url, self.page_query_param, page_number)
  
      def get_previous_link(self):
          if not self.page.has_previous():
              return None
          url = self.request and self.request.get_full_path() or ''
          url = url.encode('utf-8')
          page_number = self.page.previous_page_number()
          return replace_query_param(url, self.page_query_param, page_number)
  
new_contents: # Copyright (c) 2015 Ansible, Inc.
  # All Rights Reserved.
  
  # Django
  from django.core.paginator import Paginator as DjangoPaginator
  from django.core.paginator import PageNotAnInteger, EmptyPage
  from django.db import connections
  
  # Django REST Framework
  from django.conf import settings
  from rest_framework import pagination
  from rest_framework.utils.urls import replace_query_param
  
  
  class Paginator(DjangoPaginator):
  
      def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):
          self.count_field = None
          # Based on http://stackoverflow.com/questions/156114/best-way-to-get-result-count-before-limit-was-applied
          # With PostgreSQL, we can use a window function to include the total
          # count of results (before limit and offset are applied) as an extra
          # column and avoid having to issue a separate COUNT(*) query.
          if hasattr(object_list, 'extra'):
              if connections[getattr(object_list, 'db', None) or 'default'].vendor == 'postgresql':
                  object_list = object_list.extra(select=dict(__count='COUNT(*) OVER()'))
                  self.count_field = '__count'
          super(Paginator, self).__init__(object_list, per_page, orphans, allow_empty_first_page)
          assert self.orphans == 0
  
      def validate_number(self, number, check_num_pages=True):
          """
          Validates the given 1-based page number.
          """
          try:
              number = int(number)
          except (TypeError, ValueError):
              raise PageNotAnInteger('That page number is not an integer')
          if number < 1:
              raise EmptyPage('That page number is less than 1')
          # Optionally skip checking num_pages, since that will result in a
          # COUNT(*) query.
          if check_num_pages and number > self.num_pages:
              if number == 1 and self.allow_empty_first_page:
                  pass
              else:
                  raise EmptyPage('That page contains no results')
          return number
  
      def page(self, number):
          """
          Returns a Page object for the given 1-based page number.
          """
          number = self.validate_number(number, check_num_pages=bool(self.count_field is None))
          bottom = (number - 1) * self.per_page
          top = bottom + self.per_page
          sub_list = self.object_list[bottom:top]
          if self.count_field and self._count is None:
              # Execute one query to fetch all results.
              sub_list = list(sub_list)
              try:
                  # Get the total count from the first result.
                  self._count = getattr(sub_list[0], self.count_field)
              except IndexError:
                  # If no results were returned, we still don't know the total
                  # count, but do know that we've reached an empty page.
                  if number > 1 or not self.allow_empty_first_page:
                      raise EmptyPage('That page contains no results')
          return self._get_page(sub_list, number, self)
  
  
  class Pagination(pagination.PageNumberPagination):
  
      page_size_query_param = 'page_size'
      max_page_size = settings.MAX_PAGE_SIZE
      django_paginator_class = Paginator
  
      def get_next_link(self):
          if not self.page.has_next():
              return None
          url = self.request and self.request.get_full_path() or ''
          url = url.encode('utf-8')
          page_number = self.page.next_page_number()
          return replace_query_param(url, self.page_query_param, page_number)
  
      def get_previous_link(self):
          if not self.page.has_previous():
              return None
          url = self.request and self.request.get_full_path() or ''
          url = url.encode('utf-8')
          page_number = self.page.previous_page_number()
          return replace_query_param(url, self.page_query_param, page_number)
  
subject: Add custom paginator to use PostgreSQL window function instead of needing a separate COUNT(*) query.