def connection_from_cursor_paginated(queryset, connection_type, edge_type, pageinfo_type, page_query=None): """Create a Connection object from a queryset, using CursorPaginator""" paginator = CursorPaginator(queryset, queryset.query.order_by) if page_query is None: page_query = PageQuery() page = paginator.page(**attr.asdict(page_query)) edges = [] for item in list(page): edge = edge_type(node=item, cursor=paginator.cursor(item)) edges.append(edge) if page: page_info = pageinfo_type( start_cursor=paginator.cursor(edges[0].node), end_cursor=paginator.cursor(edges[-1].node), has_previous_page=page.has_previous, has_next_page=page.has_next, ) else: page_info = pageinfo_type( start_cursor=None, end_cursor=None, has_previous_page=False, has_next_page=False, ) return connection_type( edges=edges, page_info=page_info, )
def test_reverse_order(self): paginator = CursorPaginator(Post.objects.all(), ('-created', '-name')) previous_page = paginator.page(first=2) self.assertSequenceEqual(previous_page, [self.items[3], self.items[2]]) cursor = paginator.cursor(previous_page[-1]) page = paginator.page(first=2, after=cursor) self.assertSequenceEqual(page, [self.items[1], self.items[0]])
def search(user_id, search_term, before=None, after=None): """Offload the expensive part of search to avoid blocking the web interface""" if not search_term: return { "results": [], "has_next": False } if before and after: raise ValueError("You can't do this.") email_subquery = models.Email.objects.viewable(user_id) inbox_subquery = models.Inbox.objects.viewable(user_id) search_qs = watson_search.search(search_term, models=(email_subquery, inbox_subquery)) page_kwargs = { "after": after, "before": before, } if before: page_kwargs["last"] = SEARCH_PAGE_SIZE else: page_kwargs["first"] = SEARCH_PAGE_SIZE paginator = CursorPaginator(search_qs, ordering=('-watson_rank', '-id')) page = paginator.page(**page_kwargs) results = { "results": [p.id for p in page], "has_next": page.has_next, "has_previous": page.has_previous, } if len(results["results"]) > 0: results["last"] = paginator.cursor(page[-1]) results["first"] = paginator.cursor(page[0]) key = create_search_cache_key(user_id, search_term, before, after) cache.set(key, results, SEARCH_TIMEOUT) return results
def chunked_queryset_iterator(queryset, size, *, ordering=('id', )): pager = CursorPaginator(queryset, ordering) after = None while True: page = pager.page(after=after, first=size) if page: yield from page.items else: return if not page.has_next: break after = pager.cursor(instance=page[-1])
def ApiListView(request): params = request.GET queryset = Video.objects.all().order_by('-published_at') page_size = 10 paginator = CursorPaginator(queryset, ordering=['-id']) if 'before' in params: before = params['before'] page = paginator.page(first=page_size, before=before) elif 'after' in params: after = params['after'] page = paginator.page(first=page_size, after=after) else: page = paginator.page(first=page_size, after=None) data = { 'objects': [VideoSerializer(p).data for p in page], 'has_next_page': page.has_next, 'has_previous_page': page.has_previous, 'last_cursor': paginator.cursor(page[-1]), 'first_cursor': paginator.cursor(page[0]) } return JsonResponse(data)
def search(user_id, search_term, before=None, after=None): """Offload the expensive part of search to avoid blocking the web interface""" if not search_term: return {"results": [], "has_next": False} if before and after: raise ValueError("You can't do this.") email_subquery = models.Email.objects.viewable(user_id) inbox_subquery = models.Inbox.objects.viewable(user_id) search_qs = watson_search.search(search_term, models=(email_subquery, inbox_subquery)) page_kwargs = { "after": after, "before": before, } if before: page_kwargs["last"] = SEARCH_PAGE_SIZE else: page_kwargs["first"] = SEARCH_PAGE_SIZE paginator = CursorPaginator(search_qs, ordering=('-watson_rank', '-id')) page = paginator.page(**page_kwargs) results = { "results": [p.id for p in page], "has_next": page.has_next, "has_previous": page.has_previous, } if len(results["results"]) > 0: results["last"] = paginator.cursor(page[-1]) results["first"] = paginator.cursor(page[0]) key = create_search_cache_key(user_id, search_term, before, after) cache.set(key, results, SEARCH_TIMEOUT) return results
def _chunked_queryset_iterator(queryset, size, *, ordering=('id', )): """ Split a queryset into chunks. This can be used instead of `queryset.iterator()`, so `.prefetch_related()` also works Note:: The ordering must uniquely identify the object, and be in the same order (ASC/DESC). See https://github.com/photocrowd/django-cursor-pagination """ pager = CursorPaginator(queryset, ordering) after = None while True: page = pager.page(after=after, first=size) if page: yield from page.items else: return if not page.has_next: break # take last item, next page starts after this. after = pager.cursor(instance=page[-1])