python - django-tables2/django-filter - 使用过滤器类进行分页

标签 python django django-filter django-tables2

下午好,

我在 django-tables2 中使用自定义 django-filter 来通过单个输入搜索所有字段。我刚刚注意到,当我搜索时,我丢失了分页菜单。

这是过滤器代码 https://spapas.github.io/2016/09/12/django-split-query/ 的链接

这是我的过滤器

class SiteFilterEx(django_filters.FilterSet):
    ex = django_filters.CharFilter(label='Ex filter', method='filter_ex')
    search_fields = ['location', 'bgp_as', 'opening_date','town','postcode']

    def filter_ex(self, qs, name, value):
        if value:
            q_parts = value.split()

            # Use a global q_totals
            q_totals = Q()

            # This part will get us all possible segmantiation of the query parts and put it in the possibilities list
            combinatorics = itertools.product([True, False], repeat=len(q_parts) - 1)
            possibilities = []
            for combination in combinatorics:
                i = 0
                one_such_combination = [q_parts[i]]
                for slab in combination:
                    i += 1
                    if not slab: # there is a join
                        one_such_combination[-1] += ' ' + q_parts[i]
                    else:
                        one_such_combination += [q_parts[i]]
                possibilities.append(one_such_combination)

            # Now, for all possiblities we'll append all the Q objects using OR
            for p in possibilities:
                list1=self.search_fields
                list2=p
                perms = [zip(x,list2) for x in itertools.permutations(list1,len(list2))]

                for perm in perms:
                    q_part = Q()
                    for p in perm:
                        q_part = q_part & Q(**{p[0]+'__icontains': p[1]})
                    q_totals = q_totals | q_part

            qs = qs.filter(q_totals)
        return qs    

    class Meta:
        model = Site
        fields = ['ex']     
        form = SiteFilterForm  

在我的模板中我可以使用:

Showing {{ filter.qs.count }} of {{ filter.queryset.count }} records 

但是默认的 Django-tables 使用

Showing {{ table.page.start_index }} to {{ table.page.end_index }} of {{ table.page.paginator.count }} records 

当我过滤时,分页完全消失了。

我想我需要如何返回同名的分页?但不确定我需要做什么?

这是 View 中的代码:

class Sites(LoginRequiredMixin, ExportMixin, SingleTableMixin, FilterView):
    model = Site
    table_class = SiteTable
    template_name = "app_settings/table_view.html"
    login_url = '/login/'
    redirect_field_name = 'redirect_to'
    filterset_class = SiteFilterEx
    exclude_columns = ("buttons", )

    def dispatch(self, *args, **kwargs):
        site_type = get_object_or_404(SiteType, pk=self.kwargs['site_type'])
        site_state = 'Open' if self.kwargs['state'] else 'Closed'
        self.site_type_name = '{} {}s'.format(site_state, site_type.site_type)
        self.site_type_icon = 'fa {}'.format(site_type.icon)
        return super(Sites, self).dispatch(*args, **kwargs)

    def get_queryset(self):
        site_type = self.kwargs['site_type']
        subnet = Subquery(
            DeviceCircuitSubnets.objects.filter(device__site_id=OuterRef('id'), \
                                        active_link=True, \
                                        circuit__decommissioned=False
                                        ).values('circuit__name')[:1])        
        active_circuit = Subquery(
            DeviceCircuitSubnets.objects.filter(device__site_id=OuterRef('id'), \
                                        active_link=True, \
                                        circuit__decommissioned=False
                                        ).values('circuit__name')[:1])
        if site_type:
            return super(Sites, self).get_queryset().filter(
                is_live=self.kwargs['state'], site_type_id=site_type
            ).annotate(
                active_circuit=active_circuit
            ).prefetch_related('sitesupernet_set')
        else:
            return super(Sites, self).get_queryset().filter(
                is_live=self.kwargs['state']
            ).annotate(
                active_circuit=active_circuit
            ).prefetch_related('sitesupernet_set')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)     
        context['page_icon']=self.site_type_icon
        context['page_title']=self.site_type_name 
        return context  

最佳答案

以下内容可能会有所帮助: https://kuttler.eu/en/post/using-django-tables2-filters-crispy-forms-together/

特别是这几行:

As SingleTableView inherits from Django's ListView you automatically get a Paginator object in the template context as paginator.

The get_queryset() method was changed to apply the filter and to return the filtered queryset. That filtered data ends up in the table in get_table() and gets paged. Aftert that it is added to the template context together with the filter.

我在我的项目中使用它来显示过滤的分页表,使用以下内容作为我的 View 的基类: https://gist.github.com/craigderington/0a7ded018b8401bc42822b2eeaaff1cd

像这样:

class PagedFilteredTableView(SingleTableView):
    filter_class = None
    formhelper_class = None
    context_filter_name = 'filter'
    paginator_class = LazyPaginator

    def get_queryset(self, **kwargs):
        qs = super(PagedFilteredTableView, self).get_queryset()
        self.filter = self.filter_class(self.request.GET, queryset=qs)
        self.filter.form.helper = self.formhelper_class()
        return self.filter.qs

    def get_context_data(self, **kwargs):
        context = super(PagedFilteredTableView, self).get_context_data()
        context[self.context_filter_name] = self.filter
        return context

使用我的 View 类:

class JobList(LoginRequiredMixin, PermissionRequiredMixin, ExportMixin, PagedFilteredTableView):

    permission_required = 'jobs.view_job'
    template_name = 'jobs/job_list.html'
    model = Job
    context_object_name = 'job_list'
    table_class = JobTable
    table_pagination = {'per_page': 20}
    filter_class = JobListFilter
    formhelper_class = forms.JobListFilterFormHelper
    # Columns to exclude in the export
    exclude_columns = ('duration', 'job_type', 'contact_name', 'job_status',)

    def get_queryset(self):
        qs = super(JobList, self).get_queryset()
        ...
        self.filter.form.helper.add_input(
            Submit('submit', 'Filter',
                   css_class='btn pmd-ripple-effect btn-lg btn-primary btn-block',
                   style='margin-top:10px;')
        )
        return qs

    def get_context_data(self, **kwargs):
        context = super(JobList, self).get_context_data(**kwargs)
        search_query = self.get_queryset()
        table = JobTable(search_query)
        RequestConfig(self.request).configure(table)
        context['table'] = table
        return context

因此,对于您的 View ,您可以将 PagedFilteredTableView 类添加到 views.py 中的 Sites 类上方,然后更改您的 Sites 类如下:

class PagedFilteredTableView(SingleTableView):
    filter_class = None
    formhelper_class = None
    context_filter_name = 'filter'
    paginator_class = LazyPaginator

    def get_queryset(self, **kwargs):
        qs = super(PagedFilteredTableView, self).get_queryset()
        self.filter = self.filter_class(self.request.GET, queryset=qs)
        self.filter.form.helper = self.formhelper_class()
        return self.filter.qs

    def get_context_data(self, **kwargs):
        context = super(PagedFilteredTableView, self).get_context_data()
        context[self.context_filter_name] = self.filter
        return context


class Sites(LoginRequiredMixin, ExportMixin, PagedFilteredTableView):
    model = Site
    table_class = SiteTable
    template_name = "app_settings/table_view.html"
    login_url = '/login/'
    redirect_field_name = 'redirect_to'
    filter_class = SiteFilterEx
    exclude_columns = ("buttons", )
    table_pagination = {'per_page': 20}

    def dispatch(self, *args, **kwargs):
        site_type = get_object_or_404(SiteType, pk=self.kwargs['site_type'])
        site_state = 'Open' if self.kwargs['state'] else 'Closed'
        self.site_type_name = '{} {}s'.format(site_state, site_type.site_type)
        self.site_type_icon = 'fa {}'.format(site_type.icon)
        return super(Sites, self).dispatch(*args, **kwargs)

    def get_queryset(self):
        site_type = self.kwargs['site_type']
        subnet = Subquery(
            DeviceCircuitSubnets.objects.filter(device__site_id=OuterRef('id'), \
                                        active_link=True, \
                                        circuit__decommissioned=False
                                        ).values('circuit__name')[:1])        
        active_circuit = Subquery(
            DeviceCircuitSubnets.objects.filter(device__site_id=OuterRef('id'), \
                                        active_link=True, \
                                        circuit__decommissioned=False
                                        ).values('circuit__name')[:1])
        if site_type:
            return super(Sites, self).get_queryset().filter(
                is_live=self.kwargs['state'], site_type_id=site_type
            ).annotate(
                active_circuit=active_circuit
            ).prefetch_related('sitesupernet_set')
        else:
            return super(Sites, self).get_queryset().filter(
                is_live=self.kwargs['state']
            ).annotate(
                active_circuit=active_circuit
            ).prefetch_related('sitesupernet_set')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)     
        context['page_icon']=self.site_type_icon
        context['page_title']=self.site_type_name 
        return context

关于python - django-tables2/django-filter - 使用过滤器类进行分页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58711278/

相关文章:

python - 当前一个值也使用组数据计算时,如何在 Pandas 数据框中使用前一行值

python - Pyspark - 为数据框定义自定义架构

python - 如何使用Python去除金相图像上的划痕

python - 了解 Django 基于类的 View 混合

python - 如何过滤私有(private)用户与用户的交互?

django - 如何在不公开数据库中字段名称的情况下使用 OrderingFilter

python - Swift 序列化使用 Python 生成的稀疏矩阵

python - django-modelstranslation 后备原始字段值

django:如何为模型管理 Hook 保存按钮?

python - 如何使用ModelMultipleChoiceFilter?