def render_table(request,
                 table,
                 links=None,
                 context=None,
                 template='tri_table/list.html',
                 blank_on_empty=False,
                 paginate_by=40,  # pragma: no mutate
                 page=None,
                 paginator=None,
                 show_hits=False,
                 hit_label='Items',
                 post_bulk_edit=lambda table, queryset, updates: None):
    """
    Render a table. This automatically handles pagination, sorting, filtering and bulk operations.

    :param request: the request object. This is set on the table object so that it is available for lambda expressions.
    :param table: an instance of Table
    :param links: a list of instances of Link
    :param context: dict of extra context parameters
    :param template: if you need to render the table differently you can override this parameter with either a name of a template to load or a `Template` instance.
    :param blank_on_empty: turn off the displaying of `{{ empty_message }}` in the template when the list is empty
    :param show_hits: Display how many items there are total in the paginator.
    :param hit_label: Label for the show_hits display.
    :return: a string with the rendered HTML table
    """
    if not context:
        context = {}

    if isinstance(table, Namespace):
        table = table()

    assert isinstance(table, Table), table
    table.request = request

    should_return, dispatch_result = handle_dispatch(request=request, obj=table)
    if should_return:
        return dispatch_result

    context['bulk_form'] = table.bulk_form
    context['query_form'] = table.query_form
    context['tri_query_error'] = table.query_error

    if table.bulk_form and request.method == 'POST':
        if table.bulk_form.is_valid():
            queryset = table.bulk_queryset()

            updates = {
                field.name: field.value
                for field in table.bulk_form.fields
                if field.value is not None and field.value != '' and field.attr is not None
            }
            queryset.update(**updates)

            post_bulk_edit(table=table, queryset=queryset, updates=updates)

            return HttpResponseRedirect(request.META['HTTP_REFERER'])

    table.context = table_context(
        request,
        table=table,
        links=links,
        paginate_by=paginate_by,
        page=page,
        extra_context=context,
        paginator=paginator,
        show_hits=show_hits,
        hit_label=hit_label,
    )

    if not table.data and blank_on_empty:
        return ''

    if table.query_form and not table.query_form.is_valid():
        table.data = None
        table.context['invalid_form_message'] = mark_safe('<i class="fa fa-meh-o fa-5x" aria-hidden="true"></i>')

    return render_template(request, template, table.context)
Render a table. This automatically handles pagination, sorting, filtering and bulk operations.

    :param request: the request object. This is set on the table object so that it is available for lambda expressions.
    :param table: an instance of Table
    :param links: a list of instances of Link
    :param context: dict of extra context parameters
    :param template: if you need to render the table differently you can override this parameter with either a name of a template to load or a `Template` instance.
    :param blank_on_empty: turn off the displaying of `{{ empty_message }}` in the template when the list is empty
    :param show_hits: Display how many items there are total in the paginator.
    :param hit_label: Label for the show_hits display.
    :return: a string with the rendered HTML table