【发布时间】:2012-11-28 18:14:15
【问题描述】:
我开始使用django-tables2(我可以从第一印象强烈推荐)并且我问自己如何实现列过滤。我没有找到合适的文档,但我确定它在某个地方。
【问题讨论】:
标签: python django django-tables2
我开始使用django-tables2(我可以从第一印象强烈推荐)并且我问自己如何实现列过滤。我没有找到合适的文档,但我确定它在某个地方。
【问题讨论】:
标签: python django django-tables2
答案有点晚,但无论如何......我也找不到任何合适的列过滤文档。有很多方法可以做到:
A.手动:我添加了一个包含我想要过滤的字段的表单,然后在我的视图中执行类似的操作:
数据 = 模型.MyClass.all() form = forms.MyFilterForm(request.GET) 如果 request.GET.get('field1'): 数据 = data.filter(field1=request.GET.get('field1') ) 如果 request.GET.get('field2'): 数据 = data.filter(field2=request.GET.get('field2') ) ... 表 = 表。我的表(数据)这很好用,但它不是那么干燥,因为它在视图中是硬编码的。
B.使用 SingleTableView:另一种方法是添加包含表单的 SingleTableView:
从 django_tables2 导入 SingleTableView 类FilteredSingleTableView(SingleTableView): def get_table_data(self): 数据=模型.MyClass.objects.all 如果 self.request.GET.get('field1'): 数据 = data.filter(field1=self.request.GET.get('field1') ) 如果 self.request.GET.get('field1'): 数据 = data.filter(field1=self.request.GET.get('field1') ) 返回数据 def get_context_data(self, **kwargs): context = super(FilteredSingleTableView, self).get_context_data(**kwargs) 上下文['form'] = forms.MyFilterForm(self.request.user, self.request.GET) 返回上下文这更干:)
C.使用 SingleTableView 和 django_filters:这可能是最 DRY 的方式 :) 下面是如何做到的:
首先定义一个过滤器:
MyFilter 类(django_filters.FilterSet): field1 = django_filters.CharFilter() field2 = django_filters.CharFilter() ...(或者你可以在 Meta 中添加模型过滤器(model = MyModel)
现在,像这样创建一个 SingleTableView
类FilteredSingleTableView(SingleTableView): def get_table_data(self): f = filters.MyFilter(self.request.GET, queryset =models.MyClass.objects.all(), request=self.request) 返回 f def get_context_data(self, **kwargs): context = super(FilteredSingleTableView, self).get_context_data(**kwargs) f = filters.MyFilter(self.request.GET, queryset =models.MyClass.objects.all(), request=self.request) 上下文['form'] = f.form 返回上下文(可能 f =... 行有问题,但我无法使其正常工作。
最后,你可以像这样从你的 urls.py 调用 SingleTableView
url(r'^$', views.FilteredSingleTableView.as_view( table_class= 表格.MyTable, 模型=模型.MyClass, template_name ='mytemplate.html', table_pagination={ "per_page":50 } )) , name='filtered_single_table_view' ),D.使用泛型类: 这是一种更加 DRY 和 django-generic-class-views 的方式!这实际上是 C 的下一步:只需像这样声明您的 FilteredSingleTableView:
类 FilteredSingleTableView(django_tables2.SingleTableView): filter_class= 无 def get_table_data(self): self.filter = self.filter_class(self.request.GET, queryset =super(FilteredSingleTableView, self).get_table_data() ) 返回 self.filter.qs def get_context_data(self, **kwargs): context = super(FilteredSingleTableView, self).get_context_data(**kwargs) 上下文['filter'] = self.filter 返回上下文现在 FilteredSingleTableView 有一个过滤器类的参数,所以你可以在你的 urls.py 中传递它以及其他参数:
url(r'^$', ship.views.FilteredSingleTableView.as_view( 模型=模型.MyModel, table_class=tables.MyTable, template_name='mytemplate.html' , filter_class= 过滤器.MyFilter, ) , name='myview'),因此,您无需修改即可使用 FilteredSingleTableView 过滤您的任何模型!
还请注意,我现在已将过滤器保存为实例变量并删除了我在 C 中的重复代码 f=filters.MyFilter(...)(get_table_data 在 get_context_data 之前调用 - 如果这并不总是那么我们可以添加一个get_filter 实例方法来解决问题)!
2016 年 4 月 23 日更新:根据大众的需求,我创建了一个简单的 Django 项目,该项目使用通用的 FilteredSingleTableView 类来过滤图书表。您可以在以下位置找到它:https://github.com/spapas/django_table_filtering
2016 年 5 月 7 日更新:请注意,您应该使用 return self.filter.qs 在 D 中返回 get_table_data(我已经更新了答案this) 否则视图将花费太长时间来呈现大表 - 更多信息可以在 https://github.com/spapas/django_table_filtering/issues/1 上找到
【讨论】:
有一种更简单、更干的方法来构建通用视图:
from django_filters.views import FilterView
from django_tables2 import SingleTableView
class FilterTableView(FilterView, SingleTableView):
def get_table_data(self):
return self.object_list
所以你可以这样做:
class MyTableView(FilterTableView):
model = MyModel
table_class = MyTable
filterset_class = MyFilter
【讨论】:
这是一个完整的工作示例,来自我使用 Django 2、Crispy Forms 和 Bootstrap 4 编写的应用程序:
urls.py:
from django.urls import path
from .views import ASTodasView
urlpatterns = [
path("asignatura/todas", ASTodasView.as_view(), name="as-todas"),
]
views.py:
from .filters import AsignaturaListFilter
from .forms import AsignaturaFilterFormHelper
from .models import Asignatura, Calendario
from .tables import AsignaturasTable
from .utils import PagedFilteredTableView
class ASTodasView(PagedFilteredTableView):
filter_class = AsignaturaListFilter
model = Asignatura
table_class = AsignaturasTable
template_name = "asignatura/todas.html"
formhelper_class = AsignaturaFilterFormHelper
def get_queryset(self):
anyo_academico = Calendario.get_anyo_academico_actual()
return Asignatura.objects.filter(anyo_academico=anyo_academico)
filters.py:
import django_filters
from .models import Asignatura
class AsignaturaListFilter(django_filters.FilterSet):
class Meta:
model = Asignatura
fields = {
"nombre_estudio": ["icontains"],
"nombre_centro": ["icontains"],
"asignatura_id": ["exact"],
"nombre_asignatura": ["icontains"],
"cod_grupo_asignatura": ["exact"],
}
order_by = ["asignatura_id"]
forms.py:
from django import forms
from django.utils.translation import gettext_lazy as _
from crispy_forms.bootstrap import FormActions, InlineField
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Div, Fieldset, Layout, Submit
class AsignaturaFilterFormHelper(FormHelper):
# See https://django-crispy-forms.readthedocs.io/en/latest/form_helper.html
form_class = "form form-inline"
form_id = "asignatura-search-form"
form_method = "GET"
form_tag = True
html5_required = True
layout = Layout(
Div(
Fieldset(
"<span class='fa fa-search'></span> " + str(_("Buscar asignatura")),
Div(
InlineField("nombre_estudio__icontains", wrapper_class="col-4"),
InlineField("nombre_centro__icontains", wrapper_class="col-4"),
InlineField("asignatura_id", wrapper_class="col-4"),
InlineField("nombre_asignatura__icontains", wrapper_class="col-4"),
InlineField("cod_grupo_asignatura", wrapper_class="col-4"),
css_class="row",
),
css_class="col-10 border p-3",
),
FormActions(
Submit("submit", _("Filtrar")),
css_class="col-2 text-right align-self-center",
),
css_class="row",
)
)
tables.py:
import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from .models import Asignatura
class AsignaturasTable(tables.Table):
class Meta:
attrs = {"class": "table table-striped table-hover cabecera-azul"}
model = Asignatura
fields = (
"nombre_estudio",
"nombre_centro",
"asignatura_id",
"nombre_asignatura",
"cod_grupo_asignatura",
)
empty_text = _(
"No hay ninguna asignatura que satisfaga los criterios de búsqueda."
)
template_name = "django_tables2/bootstrap4.html"
per_page = 20
utils.py:
from django_tables2 import SingleTableView
class PagedFilteredTableView(SingleTableView):
filter_class = None
formhelper_class = None
context_filter_name = "filter"
def get_table_data(self):
self.filter = self.filter_class(
self.request.GET, queryset=super().get_table_data()
)
self.filter.form.helper = self.formhelper_class()
return self.filter.qs
def get_context_data(self, **kwargs):
context = super(PagedFilteredTableView, self).get_context_data(**kwargs)
context[self.context_filter_name] = self.filter
return context
todas.html:
{% extends 'base.html' %}
{% load crispy_forms_tags i18n %}
{% load render_table from django_tables2 %}
{% block title %}{% trans "Todas las asignaturas" %}{% endblock title %}
{% block content %}
<div class="container-blanco">
<h1>{% trans "Todas las asignaturas" %}</h1>
<hr />
<br />
{% crispy filter.form filter.form.helper %}
<br />
{% render_table table %}
</div>
{% endblock content %}
希望对您有所帮助。欢迎改进。
【讨论】:
如果您更喜欢将 django_tables2.views.SingleTableMixin 与 Django 的 ListView 或其子类(而不是 SingleTableView)一起使用,我建议如下:
class FilteredListViewMixin(object):
""" Uses django-filter to filter a ListView. """
filter_class = None
def get_queryset(self):
qs = super(FilteredListViewMixin, self).get_queryset()
self.filter = self.filter_class(self.request.GET,
queryset=qs)
return self.filter.qs
def get_context_data(self, **kwargs):
context = super(FilteredListViewMixin, self).get_context_data(**kwargs)
context['filter'] = self.filter
return context
它具有不与django-tables2 (DRY FTW) 耦合的额外好处,这意味着它也可以与通用ListViews 一起使用。
【讨论】: