Example #1
0
    def get_links(self):
        """Returns all links used in the payload.

        By default, this only includes pagination links. Subclasses can
        provide additional links.
        """
        links = {}

        full_path = self.request.build_absolute_uri(self.request.path)

        query_parameters = get_url_params_except(
            self.request.GET, self.start_param, self.max_results_param)

        if query_parameters:
            query_parameters = '&' + query_parameters

        if self.has_prev():
            links[self.prev_key] = {
                'method': 'GET',
                'href': self.build_pagination_url(
                    full_path, self.get_prev_index(),
                    self.max_results, query_parameters),
            }

        if self.has_next():
            links[self.next_key] = {
                'method': 'GET',
                'href': self.build_pagination_url(
                    full_path, self.get_next_index(),
                    self.max_results, query_parameters),
            }

        return links
Example #2
0
    def __init__(self, request, queryset, results_key="results",
                 prev_key="prev", next_key="next",
                 total_results_key="total_results",
                 default_max_results=25, max_results_cap=200,
                 serialize_object_func=None,
                 extra_data={}, *args, **kwargs):
        try:
            start = max(int(request.GET.get('start', 0)), 0)
        except ValueError:
            start = 0

        try:
            max_results = \
                min(int(request.GET.get('max-results', default_max_results)),
                    max_results_cap)
        except ValueError:
            max_results = default_max_results

        results = queryset[start:start + max_results]

        total_results = queryset.count()

        if total_results == 0:
            results = []
        elif serialize_object_func:
            results = [serialize_object_func(obj)
                       for obj in results]
        else:
            results = list(results)

        data = {
            results_key: results,
            total_results_key: total_results,
        }
        data.update(extra_data)

        full_path = request.build_absolute_uri(request.path)

        query_parameters = get_url_params_except(request.GET,
                                                 'start', 'max-results')
        if query_parameters:
            query_parameters = '&' + query_parameters

        if start > 0:
            data['links'][prev_key] = {
                'method': 'GET',
                'href': '%s?start=%s&max-results=%s%s' %
                        (full_path, max(start - max_results, 0), max_results,
                         query_parameters),
            }

        if start + len(results) < total_results:
            data['links'][next_key] = {
                'method': 'GET',
                'href': '%s?start=%s&max-results=%s%s' %
                        (full_path, start + max_results, max_results,
                         query_parameters),
            }

        WebAPIResponse.__init__(self, request, obj=data, *args, **kwargs)
Example #3
0
def querystring_with(context, attr, value):
    """Helper for querystring manipulation.

    Often, we'll want to update only a single value in a querystring without
    changing the others. This tag helps with that.
    """
    existing_query = get_url_params_except(context['request'].GET, attr)
    new_query = urlencode({attr.encode('utf-8'): value.encode('utf-8')})

    if existing_query:
        return '?%s&%s' % (existing_query, new_query)
    else:
        return '?%s' % new_query
Example #4
0
def querystring_with(context, attr, value):
    """Helper for querystring manipulation.

    Often, we'll want to update only a single value in a querystring without
    changing the others. This tag helps with that.
    """
    existing_query = get_url_params_except(context['request'].GET, attr)
    new_query = urlencode({attr.encode('utf-8'): value.encode('utf-8')})

    if existing_query:
        return '?%s&%s' % (existing_query, new_query)
    else:
        return '?%s' % new_query
Example #5
0
    def render_listview(self, render_context=None):
        """
        Renders the standard list view of the grid.

        This can be called from templates.
        """
        try:
            if render_context is None:
                render_context = self._build_render_context()

            self.load_state(render_context)

            extra_query = get_url_params_except(self.request.GET, 'page')

            context = {
                'datagrid': self,
                'is_paginated': self.page.has_other_pages(),
                'results_per_page': self.paginate_by,
                'has_next': self.page.has_next(),
                'has_previous': self.page.has_previous(),
                'page': self.page.number,
                'last_on_page': self.page.end_index(),
                'first_on_page': self.page.start_index(),
                'pages': self.paginator.num_pages,
                'hits': self.paginator.count,
                'page_range': self.paginator.page_range,
                'extra_query': extra_query,
            }

            if self.page.has_next():
                context['next'] = self.page.next_page_number()
            else:
                context['next'] = None

            if self.page.has_previous():
                context['previous'] = self.page.previous_page_number()
            else:
                context['previous'] = None

            context.update(self.extra_context)
            context.update(render_context)

            return mark_safe(render_to_string(self.listview_template,
                                              Context(context)))
        except Exception:
            trace = traceback.format_exc();
            logging.error('Failed to render datagrid:\n%s' % trace,
                          extra={
                              'request': self.request,
                          })
            return mark_safe('<pre>%s</pre>' % trace)
Example #6
0
def querystring_with(context, attr, value):
    """Return the current page URL with a new query string argument added.

    This makes it easy to add to or replace part of a query string for the
    current page's URL, which may already contain a query string.

    If the page URL already has a query string, a new item is added in the form
    of ``&attr=value``. If it doesn't have a query string, this will start a
    new one in the form of ``?attr=value``.

    If the attribute already exists in the query string, its value will be
    replaced.

    Args:
        context (django.template.context.RequestContext):
            The Django template rendering context.

        attr (unicode):
            The name of the attribute for the new query string argument.

        value (unicode):
            The value of the attribute for the new query string argument.

    Returns:
        unicode:
        The new URL with the modified query string.

    Example:
        .. code-block:: html+django

           <a href="{% querystring_with "sorted" "1" %}">Sort</a>
    """
    warnings.warn(
        '{%% querystring_with "%(attr)s" "%(value)s" %%} is deprecated and '
        'will be removed in a future version of Djblets. Please use '
        '{%% querystring "mode" "%(attr)s=%(value)s" %%} instead.'
        % {
            'attr': attr,
            'value': value,
        },
        RemovedInDjblets30Warning)

    existing_query = get_url_params_except(context['request'].GET, attr)
    new_query = urlencode({attr.encode('utf-8'): value.encode('utf-8')})

    if existing_query:
        result = '?%s&%s' % (existing_query, new_query)
    else:
        result = '?%s' % new_query

    return escape(result)
Example #7
0
def querystring_with(context, attr, value):
    """Return the current page URL with a new query string argument added.

    This makes it easy to add to or replace part of a query string for the
    current page's URL, which may already contain a query string.

    If the page URL already has a query string, a new item is added in the form
    of ``&attr=value``. If it doesn't have a query string, this will start a
    new one in the form of ``?attr=value``.

    If the attribute already exists in the query string, its value will be
    replaced.

    Args:
        context (django.template.context.RequestContext):
            The Django template rendering context.

        attr (unicode):
            The name of the attribute for the new query string argument.

        value (unicode):
            The value of the attribute for the new query string argument.

    Returns:
        unicode:
        The new URL with the modified query string.

    Example:
        .. code-block:: html+django

           <a href="{% querystring_with "sorted" "1" %}">Sort</a>
    """
    warnings.warn(
        '{%% querystring_with "%(attr)s" "%(value)s" %%} is deprecated and '
        'will be removed in a future version of Djblets. Please use '
        '{%% querystring "mode" "%(attr)s=%(value)s" %%} instead.'
        % {
            'attr': attr,
            'value': value,
        },
        RemovedInDjblets30Warning)

    existing_query = get_url_params_except(context['request'].GET, attr)
    new_query = urlencode({attr.encode('utf-8'): value.encode('utf-8')})

    if existing_query:
        result = '?%s&%s' % (existing_query, new_query)
    else:
        result = '?%s' % new_query

    return escape(result)
Example #8
0
    def render_paginator(self, adjacent_pages=3):
        """Renders the paginator for the datagrid.

        This can be called from templates.
        """
        extra_query = get_url_params_except(self.request.GET,
                                            'page', 'gridonly',
                                            *self.special_query_args)

        page_nums = range(max(1, self.page.number - adjacent_pages),
                          min(self.paginator.num_pages,
                              self.page.number + adjacent_pages)
                          + 1)

        if extra_query:
            extra_query += '&'

        context = {
            'is_paginated': self.page.has_other_pages(),
            'hits': self.paginator.count,
            'results_per_page': self.paginate_by,
            'page': self.page.number,
            'pages': self.paginator.num_pages,
            'page_numbers': page_nums,
            'has_next': self.page.has_next(),
            'has_previous': self.page.has_previous(),
            'show_first': 1 not in page_nums,
            'show_last': self.paginator.num_pages not in page_nums,
            'extra_query': extra_query,
        }

        if self.page.has_next():
            context['next'] = self.page.next_page_number()
        else:
            context['next'] = None

        if self.page.has_previous():
            context['previous'] = self.page.previous_page_number()
        else:
            context['previous'] = None

        context.update(self.extra_context)

        return mark_safe(render_to_string(self.paginator_template,
                                          Context(context)))
Example #9
0
    def render_paginator(self, adjacent_pages=3):
        """Renders the paginator for the datagrid.

        This can be called from templates.
        """
        extra_query = get_url_params_except(self.request.GET, 'page',
                                            *self.special_query_args)

        page_nums = range(
            max(1, self.page.number - adjacent_pages),
            min(self.paginator.num_pages, self.page.number + adjacent_pages) +
            1)

        if extra_query:
            extra_query += '&'

        context = {
            'is_paginated': self.page.has_other_pages(),
            'hits': self.paginator.count,
            'results_per_page': self.paginate_by,
            'page': self.page.number,
            'pages': self.paginator.num_pages,
            'page_numbers': page_nums,
            'has_next': self.page.has_next(),
            'has_previous': self.page.has_previous(),
            'show_first': 1 not in page_nums,
            'show_last': self.paginator.num_pages not in page_nums,
            'extra_query': extra_query,
        }

        if self.page.has_next():
            context['next'] = self.page.next_page_number()
        else:
            context['next'] = None

        if self.page.has_previous():
            context['previous'] = self.page.previous_page_number()
        else:
            context['previous'] = None

        context.update(self.extra_context)

        return mark_safe(
            render_to_string(self.paginator_template, Context(context)))
Example #10
0
    def get_toggle_url(self, state):
        """
        Returns the URL of the current page with this column's visibility
        toggled.
        """
        columns = [column.id for column in state.datagrid.columns]

        if state.active:
            try:
                columns.remove(self.id)
            except ValueError:
                pass
        else:
            columns.append(self.id)

        url_params = get_url_params_except(state.datagrid.request.GET,
                                           'columns')
        if url_params:
            url_params = url_params + '&'

        return "?%scolumns=%s" % (url_params, ",".join(columns))
Example #11
0
    def get_toggle_url(self, state):
        """
        Returns the URL of the current page with this column's visibility
        toggled.
        """
        columns = [column.id for column in state.datagrid.columns]

        if state.active:
            try:
                columns.remove(self.id)
            except ValueError:
                pass
        else:
            columns.append(self.id)

        url_params = get_url_params_except(state.datagrid.request.GET,
                                           'columns')
        if url_params:
            url_params = url_params + '&'

        return "?%scolumns=%s" % (url_params, ",".join(columns))
Example #12
0
def querystring_with(context, attr, value):
    """Return the current page URL with a new query string argument added.

    This makes it easy to add to or replace part of a query string for the
    current page's URL, which may already contain a query string.

    If the page URL already has a query string, a new item is added in the form
    of ``&attr=value``. If it doesn't have a query string, this will start a
    new one in the form of ``?attr=value``.

    If the attribute already exists in the query string, its value will be
    replaced.

    Args:
        attr (unicode):
            The name of the attribute for the new query string argument.

        value (unicode):
            The value of the attribute for the new query string argument.

    Returns:
        unicode:
        The new URL with the modified query string.

    Example:
        .. code-block:: html+django

           <a href="{% querystring_with "sorted" "1" %}">Sort</a>
    """
    existing_query = get_url_params_except(context['request'].GET, attr)
    new_query = urlencode({attr.encode('utf-8'): value.encode('utf-8')})

    if existing_query:
        result = '?%s&%s' % (existing_query, new_query)
    else:
        result = '?%s' % new_query

    return escape(result)
Example #13
0
    def get_header(self, state):
        """
        Displays a sortable column header.

        The column header will include the current sort indicator, if it
        belongs in the sort list. It will also be made clickable in order
        to modify the sort order appropriately, if sortable.
        """
        datagrid = state.datagrid
        in_sort = False
        sort_direction = self.SORT_DESCENDING
        sort_primary = False
        sort_url = ""
        unsort_url = ""

        if self.sortable:
            sort_list = list(datagrid.sort_list)

            if sort_list:
                rev_column_id = "-%s" % self.id
                new_column_id = self.id
                cur_column_id = ""

                if self.id in sort_list:
                    # This column is currently being sorted in
                    # ascending order.
                    sort_direction = self.SORT_ASCENDING
                    cur_column_id = self.id
                    new_column_id = rev_column_id
                elif rev_column_id in sort_list:
                    # This column is currently being sorted in
                    # descending order.
                    sort_direction = self.SORT_DESCENDING
                    cur_column_id = rev_column_id
                    new_column_id = self.id

                if cur_column_id:
                    in_sort = True
                    sort_primary = (sort_list[0] == cur_column_id)

                    if not sort_primary:
                        # If this is not the primary column, we want to keep
                        # the sort order intact.
                        new_column_id = cur_column_id

                    # Remove this column from the current location in the list
                    # so we can move it to the front of the list.
                    sort_list.remove(cur_column_id)

                # Insert the column name into the beginning of the sort list.
                sort_list.insert(0, new_column_id)
            else:
                # There's no sort list to begin with. Make this column
                # the only entry.
                sort_list = [self.id]

            # We can only support two entries in the sort list, so truncate
            # this.
            del(sort_list[2:])

            url_params = get_url_params_except(
                datagrid.request.GET,
                "sort", "datagrid-id", "gridonly", "columns")
            if url_params:
                url_params = url_params + '&'

            url_prefix = "?%ssort=" % url_params
            unsort_url = url_prefix + ','.join(sort_list[1:])
            sort_url   = url_prefix + ','.join(sort_list)

        ctx = Context({
            'column': self,
            'column_state': state,
            'in_sort': in_sort,
            'sort_ascending': sort_direction == self.SORT_ASCENDING,
            'sort_primary': sort_primary,
            'sort_url': sort_url,
            'unsort_url': unsort_url,
        })

        return mark_safe(datagrid.column_header_template_obj.render(ctx))
Example #14
0
    def get_header(self, state):
        """
        Displays a sortable column header.

        The column header will include the current sort indicator, if it
        belongs in the sort list. It will also be made clickable in order
        to modify the sort order appropriately, if sortable.
        """
        datagrid = state.datagrid
        in_sort = False
        sort_direction = self.SORT_DESCENDING
        sort_primary = False
        sort_url = ""
        unsort_url = ""

        if self.sortable:
            sort_list = list(datagrid.sort_list)

            if sort_list:
                rev_column_id = "-%s" % self.id
                new_column_id = self.id
                cur_column_id = ""

                if self.id in sort_list:
                    # This column is currently being sorted in
                    # ascending order.
                    sort_direction = self.SORT_ASCENDING
                    cur_column_id = self.id
                    new_column_id = rev_column_id
                elif rev_column_id in sort_list:
                    # This column is currently being sorted in
                    # descending order.
                    sort_direction = self.SORT_DESCENDING
                    cur_column_id = rev_column_id
                    new_column_id = self.id

                if cur_column_id:
                    in_sort = True
                    sort_primary = (sort_list[0] == cur_column_id)

                    if not sort_primary:
                        # If this is not the primary column, we want to keep
                        # the sort order intact.
                        new_column_id = cur_column_id

                    # Remove this column from the current location in the list
                    # so we can move it to the front of the list.
                    sort_list.remove(cur_column_id)

                # Insert the column name into the beginning of the sort list.
                sort_list.insert(0, new_column_id)
            else:
                # There's no sort list to begin with. Make this column
                # the only entry.
                sort_list = [self.id]

            # We can only support two entries in the sort list, so truncate
            # this.
            del (sort_list[2:])

            url_params = get_url_params_except(datagrid.request.GET, "sort",
                                               "datagrid-id", "gridonly",
                                               "columns")
            if url_params:
                url_params = url_params + '&'

            url_prefix = "?%ssort=" % url_params
            unsort_url = url_prefix + ','.join(sort_list[1:])
            sort_url = url_prefix + ','.join(sort_list)

        ctx = Context({
            'column': self,
            'column_state': state,
            'in_sort': in_sort,
            'sort_ascending': sort_direction == self.SORT_ASCENDING,
            'sort_primary': sort_primary,
            'sort_url': sort_url,
            'unsort_url': unsort_url,
        })

        return mark_safe(datagrid.column_header_template_obj.render(ctx))