首页 > 解决方案 > Django_Tables2 带过滤器的动态列

问题描述

目标是为用户实现一个简单的视图,以便通过一些添加的计算信息(在某些特定列上的注释)动态选择列,并让他们过滤字段。

感谢您的任何评论,因为这花了我好几个小时才能让它正常工作我想我会为任何看到类似问题的人提供一个简短的文章:)

使用的模块/库等:Django-Filter Django_Tables2 Bootstrap-Select 以正确显示多项选择字段

我们想使用的示例模型:

class Summary(models.Model):
    billing_date = models.DateField(verbose_name='Billing Date')
    period = models.CharField(max_length=10, verbose_name='Period')
    operator = models.CharField(max_length=50, verbose_name='Operator')
    product = models.CharField(max_length=30, verbose_name='Product')
    ...

标签: djangodjango-filterdjango-tables2

解决方案


过滤器非常简单,这里唯一的特殊情况是我们最初需要一个空查询集,并且应该需要一些字段。

“info”将保存我们“Summary”模型的选择列,“product”和“operator”只是Summary中的字段。

class AdHocReportFilter(django_filters.FilterSet):
    info = django_filters.MultipleChoiceFilter(choices=report_field_choices, label='Available Fields', required=True)
    product = django_filters.ModelChoiceFilter(queryset=Product.objects.all(), label='Products', required=True)
    operator = django_filters.CharFilter(field_name="operator", lookup_expr='contains', label='Operator')
    ....

    def __init__(self, *args, **kwargs):
        super(AdHocReportFilter, self).__init__(*args, **kwargs)
        if self.data == {}:
            self.queryset = self.queryset.none()

模板:这里没有什么有趣的展示,你可以使用 Bootstrap-Select 来整理你的多选字段(有很多关于它的不错的文章)。确保将您的表格放入“如果”,因为该对象可能存在也可能不存在,具体取决于您的视图(如果有人想要模板示例,请告诉我)

查看:相应地提取您的 GET 请求(作为列表或简单值,具体取决于您的可用过滤器)。

实际的过滤器本身取决于您希望用户能够过滤的内容,请确保将所有必要的字段设为必填或将它们替换为一些标准值,因为过滤器将不接受无类型。“field__contains”是您的朋友,因为它还会在未选择的字段上显示值!特殊情况,如果在特定字段的数据库中实际上可以有“空”值,请将它们移动到另一个过滤器,如下面的 Q - 查询示例!

幸运的是,“values”接受“*list”,这是我们所有可用列的简单列表。注释仅取决于您想要实现的目标。

使用添加的参数“user_columns”调用表对象,该参数包含我们的列表,以便我们可以构建所需的表。

@login_required
def ad_hoc_report(request):
    template_name = 'non_voice/ad_hoc_report.html'
    filter = AdHocReportFilter(request.GET, queryset=Summary.objects.all())

    info = request.GET.getlist('info', None)
    product = request.GET.get('product', '')
    operator = request.GET.get('operator', '')
    start_date = request.GET.get('start_date', None)
    end_date = request.GET.get('end_date', None)


    if operator is None:
        operator = ''

    result_object = Summary.objects.filter(product__contains=product, ).filter((Q(operator__contains=operator)|Q(operator__isnull=True)).values(*info).annotate(
        Amount=Sum("amount"), Count=Sum("count"))
    table = AdHocReportTable(data=result_object, user_columns=info)
    return render(request, template_name, {'filter': filter, 'table': table})

表:这是困难的部分,只有通过大量阅读各种堆栈溢出注释才能实现 :)

首先定义您计算的注释列并设置所需的元信息,“...”是一个内置的占位符,无需提前知道列名(这有助于我们将计算的列移动到表格的末尾)

在初始化中,我们首先检查我们的“self.base_columns”是否与我们提供的一致,并删除用户取消选择的列,否则即使过滤后仍然显示为空。(也许有更好的方法来做到这一点,还没有找到)

在下一步中,从我们在views.py中传递的上述“user_columns”中动态添加我们的用户选择的列

class AdHocReportTable(tables.Table):
    Amount = tables.Column(verbose_name='Amount')
    Count = tables.Column(verbose_name='Count')

    class Meta:
        # '...' is a built in placeholder!
        sequence = ('...', 'Amount', 'Count')
        template_name = "django_tables2/bootstrap4.html"
        attrs = {'class': 'table table-hover', }

    # This makes it possible to pass a dynamic list of columns to the Table Object
    def __init__(self, data, user_columns, *args, **kwargs):

        if user_columns:
            calulated_columns = ['Amount', 'Count']

            # Removes deselected columns from the table (otherwise they are shown empty)
            for key, val in self.base_columns.items():
                if key not in user_columns and key not in calulated_columns:
                    del self.base_columns[key]

            # Add the Selected Columns dynamically to the Table
            for col in user_columns:
                self.base_columns[col] = tables.Column(verbose_name=col)

        super(AdHocReportTable, self).__init__(data, user_columns, *args, **kwargs)


推荐阅读