【问题标题】:Handle django-filter form with split fields using django-crispy-forms使用 django-crispy-forms 处理带有拆分字段的 django-filter 表单
【发布时间】:2014-02-22 08:19:39
【问题描述】:

我有一个使用django-filter 过滤的django-tables2 表。我已经实施了一个基于来自this great answer选项 D 的方案。

但是,我使用 django-crispy-forms 和 bootstrap3 进行表单渲染。这很好用,直到我想应用 RangeFilter,它会吐出两个字段(一个最小值和最大值字段)。

我得到的输出是

我想手动控制这些字段中的每一个,这样我就可以分别对它们进行 PrependedAppendedText。

有什么想法吗?

views.py

from crispy_forms.bootstrap import PrependedAppendedText, FormActions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit, Button
from django_tables2 import SingleTableView
from aids.filters import AidFilter
import os

class FilteredSingleTableView(SingleTableView):
    filter_class = None

    def get_table_data(self):
        self.filter = AidFilter(
            self.request.GET,
            queryset=super(FilteredSingleTableView, self).get_table_data(),
        )
        self.filter.helper = FormHelper()
        self.filter.helper.form_id = 'id_filterForm'
        self.filter.helper.form_class = 'form-inline'
        self.filter.helper.form_method = 'get'
        self.filter.helper.form_tag = True
        self.filter.helper.field_template = os.path.join('bootstrap3', 'layout', 'inline_field.html')

        self.filter.helper.layout = Layout(
            'name',
            PrependedAppendedText('price', '$', 'min', ),
            # Fieldset(
                # 'Filter by price',
                # PrependedAppendedText('price_0', '$', 'min', id='id_price_0'),
                # PrependedAppendedText('price_1', '$', 'max', id='id_price_1'),
            # ),
            'maint',
            'post',
            'supplier',
            FormActions(
                Submit('submit_filter', 'Filter', css_class='btn-primary'),
                Button('clear', 'Clear', css_class='btn-sm')
            )
        )

        return self.filter

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

filters.py

import django_filters
from aids.models import Aid

class AidFilter(django_filters.FilterSet):
    name = django_filters.CharFilter(lookup_type='contains')
    price = django_filters.RangeFilter()

    class Meta:
        model = Aid
        fields = ['name', 'price', 'maint', 'post', 'supplier']

view_table.html

{% extends 'base.html' %}

{% block title %}{{ title }}{% endblock %}

{% block extra_css %}
    <link rel="stylesheet" href="{{ STATIC_URL }}django_tables2/themes/paleblue/css/screen.css" />
{% endblock %}

{% load render_table from django_tables2 %}
{% load crispy_forms_tags %}

{% block heading %}
    {{ title }}
{% endblock %}

{% block content %}
    {% crispy filter.form filter.helper %}
    {% render_table table %}
{% endblock %}

urls.py

from django.conf.urls import patterns, include, url
from django.conf.urls.static import static
from django.contrib import admin
from aids.filters import AidFilter
from aids.models import Aid
from aids.tables import AidTable
from sadb import settings
from aids.views import FilteredSingleTableView

admin.autodiscover()

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^aid_form/', 'aids.views.aid_form'),
    url(r'^supplier_form/', 'aids.views.supplier_form'),
    url(r'^view_aids/', 'aids.views.view_aids'),
    url(
        r'^$', FilteredSingleTableView.as_view(
            model=Aid,
            table_class=AidTable,
            template_name='view_table.html',
            filter_class=AidFilter
        ), name='filtered_view'
    ),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

【问题讨论】:

    标签: python django django-crispy-forms django-filter


    【解决方案1】:

    我在覆盖DateRangeFilter 后遇到了类似的问题,并通过修改小部件输出以使用带有form-inline 类的div 包装器来解决它,并在小部件末尾的def format_output()类。

    https://docs.google.com/file/d/0BwIBq4D09D0RaDZGTWhCWnJaZU0 的屏幕截图(信誉不允许我发布图片!)

    我的完整代码如下(原文取自https://groups.google.com/d/msg/django-filter/lbi_B4zYq4M/37s63u0WrncJ

    class DateRangeWidget(forms.MultiWidget):
        def __init__(self, attrs=None):
            attrs_from = {'class': 'date-from'}
            attrs_to = {'class': 'date-to'}
    
            if attrs:
                attrs_from.update(attrs)
                attrs_to.update(attrs)
    
            widgets = (forms.TextInput(attrs=attrs_from), forms.TextInput(attrs=attrs_to))
            super(DateRangeWidget, self).__init__(widgets, attrs)
    
        def decompress(self, value):
            if value:
                return [value.start, value.stop]
            return [None, None]
    
        def format_output(self, rendered_widgets):
            return '<div class="date-range form-inline">' + ' - '.join(rendered_widgets) + '</div>'
    
    
    class DateRangeField(forms.MultiValueField):
        widget = DateRangeWidget
    
        def __init__(self, *args, **kwargs):
            fields = (
                forms.DateField(),
                forms.DateField(),
            )
            super(DateRangeField, self).__init__(fields, *args, **kwargs)
    
        def compress(self, data_list):
            if data_list:
                return slice(*data_list)
            return None
    
    
    class DateRangeFilter(Filter):
        field_class = DateRangeField
    
        def filter(self, qs, value):
            date_start = datetime.datetime.combine(value.start, datetime.time(0, 0, 0))
            date_stop = datetime.datetime.combine(value.stop, datetime.time(23, 59, 59))
    
            if value:
                lookup = '%s__range' % self.name
                return qs.filter(**{lookup: (date_start, date_stop)})
            return qs
    

    【讨论】:

      猜你喜欢
      • 2019-12-31
      • 2013-07-21
      • 2014-12-21
      • 2021-01-08
      • 2022-01-04
      • 1970-01-01
      • 2016-12-20
      • 2021-05-29
      • 2014-12-07
      相关资源
      最近更新 更多