def page(self, number): """ Returns a page object. This class overrides the default behavior and ignores "orphans" and assigns the count from the ES result to the Paginator. """ number = self.validate_number(number) bottom = (number - 1) * self.per_page top = bottom + self.per_page # Force the search to evaluate and then attach the count. We want to # avoid an extra useless query even if there are no results, so we # directly fetch the count from hits. result = self.object_list[bottom:top].execute() page = Page(result.hits, number, self) # Update the `_count`. self._count = page.object_list.total # Also store the aggregations, if any. if hasattr(result, 'aggregations'): page.aggregations = result.aggregations # Now that we have the count validate that the page number isn't higher # than the possible number of pages and adjust accordingly. if number > self.num_pages: if number == 1 and self.allow_empty_first_page: pass else: raise EmptyPage('That page contains no results') return page
def build_page(self): """For some reason occasionally the default pagination contains Nones (probably a bug in django-haystack. We don't want that.""" # Copied from super() try: page_no = int(self.request.GET.get('page', 1)) except (TypeError, ValueError): raise Http404("Not a valid number for page.") if page_no < 1: raise Http404("Pages should be 1 or greater.") start_offset = (page_no - 1) * self.results_per_page self.results = self.results.load_all() # Force haystack to pull all 'Product' objects at the same time self.results[start_offset:start_offset + self.results_per_page] paginator = Paginator(self.results, self.results_per_page) # My stuff try: page = paginator.page(page_no) except EmptyPage: page = Page([], page_no, paginator) page.object_list = [o for o in page.object_list if o is not None] return paginator, page
def _get_page(self, *args, **kwargs): page = Page(*args, **kwargs) if page.has_next(): page.next_page_first_item = page[-1] page.object_list = page.object_list[:-1] else: page.next_page_first_item = None return page
def test_paginator_tags(snapshot): objects = ['object %d' % i for i in range(100)] paginator = Paginator(objects, 5) template = loader.get_template('cruds_mixins/partials/pagination.html') page = Page(objects, 1, paginator) c = {'page_obj': page, 'is_paginated': True} result = template.render(c) snapshot.assert_match(result) page = Page(objects, 15, paginator) c = {'page_obj': page, 'is_paginated': True} result = template.render(c) snapshot.assert_match(result)
def by_storyteller(obj): if isinstance(obj, User): user = obj else: user = obj.owner template_name = "maps/_widget_by_storyteller.html" maps_page = Page([], 0, _by_storyteller_pager(None, user, 'maps')) layers_page = Page([], 0, _by_storyteller_pager(None, user, 'layers')) return loader.render_to_string(template_name, { 'user': user, 'maps_pager': maps_page, 'layers_pager': layers_page })
def page(self, number): "Returns a Page object for the given 1-based page number." number = self.validate_number(number) if self.count == 0: return Page(self.object_list, number, self) bottom = (number - 1) * self.per_page bottomdate = self.parentcomments[bottom].sortdate top = bottom + self.per_page if top + self.orphans >= self.count: object_list = self.object_list.filter(sortdate__lte=bottomdate) else: topdate = self.parentcomments[bottom+self.per_page-1].sortdate object_list = self.object_list.filter( sortdate__range=(topdate, bottomdate)) return Page(object_list, number, self)
def page(self, number): """ Returns a page object. This class overrides the default behavior and ignores "orphans" and assigns the count from the ES result to the Paginator. """ number = self.validate_number(number) bottom = (number - 1) * self.per_page top = bottom + self.per_page if top > self.max_result_window: raise InvalidPage( 'That page number is too high for the current page size') # Force the search to evaluate and then attach the count. We want to # avoid an extra useless query even if there are no results, so we # directly fetch the count from hits. result = self.object_list[bottom:top].execute() # Overwrite `object_list` with the list of ES results. page = Page(result.hits, number, self) # Overwrite the `count` with the total received from ES results. self.count = int(page.object_list.total) # Now that we have the count validate that the page number isn't higher # than the possible number of pages and adjust accordingly. if number > self.num_pages: if number == 1 and self.allow_empty_first_page: pass else: raise EmptyPage('That page contains no results') return page
def page(self, number): """ Override the page method in Paginator since Solr has already paginated stuff for us. """ number = self.validate_number(number) return Page(self.object_list, number, self)
def page(self, number): number = self.validate_number(number) offset = (number - 1) * self.per_page if offset + self.per_page + self.orphans >= self.count: top = self.count return Page(self.object_list.fetch(self.per_page, offset=offset), number, self)
def page(self, number): """ Returns a page object. """ # Don't fetch hits, only care about aggregations. self.object_list._params['search_type'] = 'count' result = self.object_list.execute() # Pull the results from the aggregations. hits = [] aggs = result.aggregations buckets = aggs['top_hits']['buckets'] for bucket in buckets: # Have to check the bucket key since other tags could get # aggregated (e.g., `featured-game`) when we only care about game # categories. if bucket['key'] in GAME_CATEGORIES: hits.append(bucket['first_game']['hits']['hits'][0]) page = Page(hits, number, self) # Update the `_count`. self._count = len(page.object_list) return page
def pagination(pager, url_name, *args): '''pager could be a page or pagination object.''' url = reverse(url_name, args=args) if not hasattr(pager, 'number'): # we're on 'page 0' - lazy load pager = Page([], 0, pager) return loader.render_to_string('_pagination.html', {'page' : pager, 'url': url})
def page(self, number): """ Returns a Page object for the given 1-based page number. This will attempt to pull the results out of the cache first, based on the requested page number. If not found in the cache, it will pull a fresh list and then cache that result + the total result count. """ if self.cache_key is None: return super(CachedPaginator, self).page(number) # In order to prevent counting the queryset # we only validate that the provided number is integer # The rest of the validation will happen when we fetch fresh data. # so if the number is invalid, no cache will be setted # number = self.validate_number(number) try: number = int(number) except (TypeError, ValueError): raise PageNotAnInteger('That page number is not an integer') page_cache_key = "%s:%s:%s" % (self.cache_key, self.per_page, number) page_data = cache.get(page_cache_key) if page_data is None: page = super(CachedPaginator, self).page(number) #cache not only the objects, but the total count too. page_data = (page.object_list, self.count) cache.set(page_cache_key, page_data, self.cache_timeout) else: cached_object_list, cached_total_count = page_data self.set_count(cached_total_count) page = Page(cached_object_list, number, self) return page
def page(self, number): number = self.validate_number(number) bottom = (number - 1) * self.per_page top = bottom + self.per_page if top + self.orphans >= self.count: top = self.count return Page(self.object_list.get_slice(bottom,self.per_page), number, self)
def page(self, number): "Returns a Page object for the given 1-based page number." number = self.validate_number(number) if self.count == 0: return Page(self.object_list, number, self) bottom = (number - 1) * self.per_page # This results in a query to the database ... bottomdate = self.parentcomments[bottom].sort_date try: # This too results in a query to the database ... top = self.parentcomments[bottom+self.per_page-1].sort_date object_list = self.object_list.filter(sort_date__range=(top, bottomdate)) except IndexError: object_list = self.object_list.filter(sort_date__lte=bottomdate) # And another (final) call to the database return Page(object_list, number, self)
def _get_page(self, *args, **kwargs): """ Return an instance of a single page. This hook can be used by subclasses to use an alternative to the standard :cls:`Page` object. """ return Page(*args, **kwargs)
def page(self, number): "Returns a Page object for the given 1-based page number." number = self.validate_number(number) offset = (number - 1) * self.per_page if offset + self.per_page + self.orphans >= self.count: top = self.count return Page(self.object_list.fetch(self.per_page, offset), number, self)
def user_list(request): current_page = request.GET.get('p', 1) current_page = int(current_page) per_page_count = request.COOKIES.get('per_page_count', 10) # 获取cookie值 per_page_count = int(per_page_count) page_obj = Page(current_page, len(LIST), per_page_count) data = LIST[page_obj.start:page_obj.end] page_str = page_obj.page_str("/user_list/") return render(request, 'user_list.html', { 'li': data, 'page_str': page_str })
def page(self, number): page = super(ObjectPaginator, self).page(number) if isinstance(page.object_list, QuerySet): ids = [product['pk'] for product in page.object_list.values('pk')] # keep same order by clause as used # in paginator to fetch full product objects ordering = page.object_list.query.order_by elif isinstance(self.object_list, SearchQuerySet): # When this step happens just after the index was cleared, then product may be None # import pdb; pdb.set_trace() # ids = [product.pk for product in page.object_list if product is not None] ids = page.object_list # ordering = self.object_list._db_query_order # our custom parameter to remember db order ordering = None else: raise if not ids: return Page([], number, self) product_set = self.model.objects.filter(id__in=ids) # ordering must by different than relevancy (relevancy occurs only in the elasticsearch part) if ordering and any(item not in ['relevancy', '-relevancy'] for item in ordering): product_set = product_set.order_by(*ordering) else: # it's a way to avoid automatically sorting by id. We want to have order which we get from the elasticsearch. # Especially useful when we search by id i.e. 400 (for this word we can find a lot of product by title and one by id). # We want to have the product which is found by id on the first position, so we should keep the list returned by solr. product_set = self.model.objects.filter(id__in=ids).extra( select={'manual': 'FIELD(id, %s)' % ','.join(map(str, ids))}, order_by=['manual'], ) # TODO: This is micro optimization for search to reduce number of queries if self.model == Booking: product_set = product_set.prefetch_related('trainer', 'trainer__user') elif self.model == Trainer: product_set = product_set.prefetch_related('user', 'diciplines') return Page(product_set, number, self)
def get_paginated_object_list(self, page_number, **kwargs): params = self.get_api_parameters(**kwargs) params['limit'] = self.per_page params['offset'] = (page_number - 1) * self.per_page result = requests.get(self.api_base_url, params=params).json() paginator = APIPaginator(result['meta']['total_count'], self.per_page) page = Page(result['items'], page_number, paginator) return (page, paginator)
def page(self, number): number = self.validate_number(number) bottom = ( number - 2) * self.per_page + self.first_page_count if number > 1 else 0 top = bottom + (self.first_page_count if number == 1 else self.per_page) if top + self.orphans >= self.count: top = self.count return Page(self.object_list[bottom:top], number, self)
def page(self, number): if number > self.num_pages: number = self.num_pages if number < 1: number = 1 bottom = (number - 1) * self.per_page top = bottom + self.per_page if top + self.orphans >= self.count: top = self.count return Page(self.object_list[bottom:top], number, self)
def __init__(self, object_list, permage_id, paginator): number = -1 self.permage_id = permage_id for page, pid in paginator.page_range: if pid == permage_id: number = page Page.__init__(self, object_list, number, paginator) self.asc = False if len(self.object_list) > 1: first = self.object_list[0].id second = self.object_list[1].id if first < second: self.asc = True #navigation: div id=paginator self.navigation = [] prev_range = self.paginator.page_range[:number-1] next_range = self.paginator.page_range[number:] if len(self.paginator.page_range) <= self.paginator.navigation_steps: self.navigation = prev_range self.navigation.append([number, "current"]) self.navigation.extend(next_range) else: steps = (self.paginator.navigation_steps-1) / 2 prev_len = len(prev_range[:steps]) next_len = len(next_range[steps*(-1):]) extra_steps_prev = steps - prev_len extra_steps_next = steps - next_len steps = steps + extra_steps_next if len(prev_range) > steps: self.navigation.append(prev_range[0]) self.navigation.append([-1, "..."]) self.navigation.extend(prev_range[(steps-1)*(-1):]) else: self.navigation.extend(prev_range[:steps]) self.navigation.append([number, "current"]) steps = ((self.paginator.navigation_steps-1) / 2) + extra_steps_prev if len(next_range) > steps: self.navigation.extend(next_range[:(steps-1)]) self.navigation.append([-1, "..."]) self.navigation.append(next_range[-1]) else: self.navigation.extend(next_range[(steps+1)*(-1):])
def page(self, number): number = self.validate_number(number) offset = (number - 1) * self.per_page limit = self.per_page if offset + limit + self.orphans >= self.count: limit = self.count - offset query_with_limit = self._get_limit_offset_query(limit, offset) data = list( self.raw_query_set.model.objects.raw(query_with_limit, self.raw_query_set.params)) return Page(data, number, self)
def extend_paginator(cls, page_items: Page): """Дополняет объект постраничной навигации. :param page_items: """ max_pages_before_after = 10 page = page_items.number min_page_before = page - max_pages_before_after if min_page_before < 1: min_page_before = 0 max_page_after = page + max_pages_before_after if max_page_after > page_items.paginator.num_pages: max_page_after = page_items.paginator.num_pages page_items.before_current = reversed( range(page - 1, min_page_before, -1)) page_items.after_current = range(page + 1, max_page_after + 1)
def page(self,number): number = self.validate_number(number) offset = (number -1 ) * self.per_page limit = self.per_page if offset + limit + self.orphans >= self.count: limit = self.count - offset database_vendor = self.connection.vendor try: query_with_limit = getattr(self,'%s_getquery' % database_vendor)(limit,offset) except AttributeError: raise DatabaseNotSupportedException('%s is not supported by RawQuerySetPaginator' % database_vendor) return Page(list(self.raw_query_set.model.objects.raw(query_with_limit,self.raw_query_set.params)), number, self)
def page(self, number): """ Returns a page object. This class overrides the default behavior and ignores "orphans" and assigns the count from the ES result to the Paginator. """ number = self.validate_number(number) bottom = (number - 1) * self.per_page top = bottom + self.per_page page = Page(self.object_list[bottom:top], number, self) # Force the search to evaluate and then attach the count. We want to # avoid an extra useless query even if there are no results, so we # directly fetch the count from hits. # Overwrite `object_list` with the list of ES results. page.object_list = page.object_list.execute().hits # Update the `_count`. self._count = page.object_list.total return page
def _get_page(self, object_list, number, paginator): self.result = object_list.execute(params=self._params) if isinstance(self.result.hits.total, int): self.count = self.result.hits.total else: self.count = int(self.result.hits.total.value) if self.count == 0 and not self.allow_empty_first_page: return 0 hits = max(1, self.count - self.orphans) self.num_pages = ceil(hits / self.per_page) return Page(self.result, number, self)
def current_page(self): try: page = int(self.request.GET['page']) if page <= 0: raise ValueError() except (ValueError, KeyError): page = self.default try: return self.page(page) except EmptyPage: return Page([], page, self)
def page(self, number): "Returns a Page object for the given 1-based page number." bottom = (number - 1) * self.per_page top = bottom + self.per_page queryset = self.object_list.fetch((number * self.per_page)+1) results = queryset[bottom:top] try: queryset[top] self._num_pages = number + 1 except IndexError: self._num_pages = number return Page(results, number, self)
def page(self, number): try: number = self.validate_number(number) self.page_num = number bottom = (number - 1) * self.per_page top = bottom + self.per_page if top + self.orphans >= self.count: top = self.count except (InvalidPage, EmptyPage, PageNotAnInteger): number = 1 bottom = 0 top = self.per_page return Page(self.object_list[bottom:top], number, self)
def page(self, number): """Returns a Page object for the given 1-based page number.""" number = self.validate_number(number) if number == 1: bottom = 0 if self.count > self.deltafirst: top = self.per_page - self.deltafirst else: top = self.per_page else: bottom = (number - 1) * self.per_page - self.deltafirst top = bottom + self.per_page if top + self.orphans >= self.count: top = self.count return Page(self.object_list[bottom:top], number, self)
def paginate(object_list, page_size, page_num): """ Takes an object_list, page_size, page_num and paginates the object list. """ paginator = Paginator(object_list, page_size) try: page = paginator.page(page_num) except PageNotAnInteger: page = paginator.page(1) except EmptyPage: page = Page([], 1, paginator) page.page_range = [] return page start = page.number - 3 if start < 0: start = 0 end = page.number + 2 if end > paginator.num_pages: end = paginator.num_pages page.page_range = paginator.page_range[start:end] return page
def __init__(self, page, req): DjangoPage.__init__(self, page.object_list, page.number, page.paginator) self.req = req
def page(self, number): """ Override the page method in Paginator since Solr has already paginated stuff for us. """ number = self.validate_number(number) # figure out the solr query and execute it solr = SolrConnection(settings.SOLR) # TODO: maybe keep connection around? start = self.per_page * (number - 1) params = {"hl.snippets": 100, # TODO: make this unlimited "hl.requireFieldMatch": 'true', # limits highlighting slop "hl.maxAnalyzedChars": '102400', # increased from default 51200 } params.update(self.facet_params) sort_field, sort_order = _get_sort(self.query.get('sort'), in_pages=True) solr_response = solr.query(self._q, fields=['id', 'title', 'date', 'month', 'day', 'sequence', 'edition_label', 'section_label'], highlight=self._ocr_list, rows=self.per_page, sort=sort_field, sort_order=sort_order, start=start, **params) solr_facets = solr_response.facet_counts # sort states by number of hits per state (desc) facets = {'state': sorted(solr_facets.get('facet_fields')['state'].items(), lambda x, y: x - y, lambda k: k[1], True), 'year': solr_facets['facet_ranges']['year']['counts'], 'county': sorted(solr_facets.get('facet_fields')['county'].items(), lambda x, y: x - y, lambda k: k[1], True)} # sort by year (desc) facets['year'] = sorted(solr_facets['facet_ranges']['year']['counts'].items(), lambda x, y: int(x) - int(y), lambda k: k[0], True) facet_gap = self.facet_params['f_year_facet_range_gap'] if facet_gap > 1: facets['year'] = [('%s-%d' % (y[0], int(y[0])+facet_gap-1), y[1]) for y in facets['year']] pages = [] for result in solr_response.results: page = models.Page.lookup(result['id']) if not page: continue words = set() coords = solr_response.highlighting[result['id']] for ocr in self._ocr_list: for s in coords.get(ocr) or []: words.update(find_words(s)) page.words = sorted(words, key=lambda v: v.lower()) page.highlight_url = self.highlight_url(page.url, page.words, number, len(pages)) pages.append(page) solr_page = Page(pages, number, self) solr_page.facets = facets return solr_page