PK 3ZFõ_À À ddh_utils/utils.pyfrom django.conf import settings from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator def create_pagination (results, results_per_page, page_number): """Returns a Paginator and Page for `results`. This function handles various possible problems with `page_number`, as per the example view code in the Django documentation. :param results: results to be paginated :type results: `django.db.models.query.QuerySet` or `list` :param results_per_page: number of results to display per page :type results_per_page: `int` :param page_number: number of current page :type page_number: `int` :rtype: `tuple` of `django.core.paginator.Paginator`, `django.core.paginator.Page` """ paginator = Paginator(results, results_per_page) try: page = paginator.page(page_number) except PageNotAnInteger: page = paginator.page(1) except EmptyPage: page = paginator.page(paginator.num_pages) return paginator, page class PaginationDisplay (object): """Class for generating data from which a full set of links to a paginated set of items may be easily rendered. The display consists of the following (in order): * A link to the previous item, if `page` is not the first. * Links to the first X pages, up to at most `page`. * An ellipsis, if the Xth page is not followed either by `page` or its Y preceding pages. * Links to up to Y pages immediately preceding `page`, if they do not overlap with the first X pages. * The current page. * Links to up to Y pages immediately following `page`. * An ellipsis, if the Yth following page is more than X pages from the last page. * Links to the last X pages, if they do not overlap with any pages listed previously. * A link to the next item, if `page` is not the last. The values of X and Y can be set in the settings module, using the attributes PAGINATION_DISPLAY_END_COUNT and PAGINATION_DISPLAY_NEAR_COUNT respectively. """ def __init__ (self, querydict): self._qd = querydict.copy() def _get_data (self, text, classes, number=None, title=None): """Returns a tuple of data representing an item to be displayed. :param text: the text of the item :type text: `str` :param classes: classes to apply to the item :type classes: `list` :param number: the number of the page this item refers to :type number: `int` :param title: the title of the item :type title: `str` :rtype: `tuple` """ url = '' if number: self._qd['page'] = number url = '?{0}'.format(self._qd.urlencode()) return (classes, url, text, title) def generate_data (self, page): """Returns a list of tuples representing the sequence of items to be displayed linking pages in the results, from the context of `page`. Each tuple consists of a list of class names, the URL destination (may be an empty string), the text, and the title. There is no HTML markup present; the elements are intended to be constructed into HTML (or even something else) in a template. :param page: context page of a set of paginated results :type page: `django.core.paginator.Page` :rtype: `list` of `tuple` """ paginator = page.paginator page_range = paginator.page_range last = paginator.num_pages data = [] current = page.number context = current - 1 # The list index of the current page # Number of pages to display at the start and end of the list. try: end_count = settings.PAGINATION_DISPLAY_END_COUNT except AttributeError: end_count = 2 # Number of pages immediately before and after current page to # display. try: near_count = settings.PAGINATION_DISPLAY_NEAR_COUNT except AttributeError: near_count = 3 if current > 1: # Add a link to the previous page. data.append(self._get_data('«', ['arrow'], current-1, 'Previous')) # Add links to the first pages. start = min(end_count, context) for number in page_range[0:start]: data.append(self._get_data(number, [], number)) if start + near_count < context: # Add an elipsis to show the gap between the first and # the preceding pages. data.append(self._get_data('…', ['unavailable'])) for number in page_range[ max(start, context-near_count):context]: data.append(self._get_data(number, [], number)) # Add the current page. data.append(self._get_data(current, ['current'], current)) if page.has_next(): # Add links to the following pages. for number in page_range[context+1:context+1+near_count]: data.append(self._get_data(number, [], number)) end = last - context - 1 - near_count if end > end_count: # Add an ellipsis to show the gap between the # following and the last pages. data.append(self._get_data('…', ['unavailable'])) if end > 0: # Add links to the last pages. for number in page_range[-min(end, end_count):]: data.append(self._get_data(number, [], number)) # Add a link to the next page. data.append(self._get_data('»', ['arrow'], current+1, 'Next')) return data PK Q°+F1×µÆÌ Ì ddh_utils/views.pyimport haystack.views import utils class BaseSearchView (object): def build_page (self): paginator, page = utils.create_pagination( self.results, self.results_per_page, self.request.GET.get('page')) return paginator, page def _extra_context (self): # Add the QueryDict of the request's GET parameters, as needed # for pagination and facet display. extra = {'querydict': self.request.GET} return extra class SearchView (BaseSearchView, haystack.views.SearchView): def extra_context (self): extra = super(SearchView, self).extra_context() extra.update(super(SearchView, self)._extra_context()) return extra class FacetedSearchView (BaseSearchView, haystack.views.FacetedSearchView): def extra_context (self): extra = super(FacetedSearchView, self).extra_context() extra.update(super(FacetedSearchView, self)._extra_context()) return extra PK Q°+F ddh_utils/__init__.pyPK Q°+F ddh_utils/models.pyPK <"G%©‹& & ( ddh_utils/templatetags/ddh_utils_tags.pyfrom django import template from ddh_utils.utils import PaginationDisplay register = template.Library() @register.inclusion_tag('includes/pagination.html') def display_pagination (qd, page): """Includes a template displaying a full pagination listing in the context of `page`. :param qd: query paramters to base URLs on :type qd: `django.http.QueryDict` :param page: context page of a set of paginated results :type page: `django.core.paginator.Page` :rtype: `dict` """ pd = PaginationDisplay(qd) return {'data': pd.generate_data(page)} @register.simple_tag def add_facet_link (qd, facet, value): """Returns a URL with `facet` and its `value` added to the query parameters in `qd`. :param qd: query paramters to base URLs on :type qd: `django.http.QueryDict`pass :param facet: name of facet to add :type facet: `str` :param value: value of facet to add :type value: `str` :rtype: `str` """ qd = qd.copy() qd['page'] = 1 facets = qd.getlist('selected_facets', []) facet_value = '{0}_exact:{1}'.format(facet, value.encode('utf-8')) if facet_value not in facets: facets.append(facet_value) qd.setlist('selected_facets', facets) return '?{0}'.format(qd.urlencode()) @register.simple_tag def remove_facet_link (qd, facet): """Returns a URL with `facet` removed from the query parameters in `qd`. :param qd: query paramters to base URLs on :type qd: `django.http.QueryDict`pass :param facet: facet (name and value combined) to remove :type facet: `str` :rtype: `str` """ qd = qd.copy() qd['page'] = 1 facets = qd.getlist('selected_facets', []) try: facets.remove(facet) except ValueError: pass return '?{0}'.format(qd.urlencode()) PK Q°+F{üÍê " ddh_utils/templatetags/__init__.py PK Q°+FN I:Š Š , ddh_utils/templates/includes/pagination.html