简体   繁体   English

使用django-crispy-forms处理带有分割字段的django-filter表单

[英]Handle django-filter form with split fields using django-crispy-forms

I have a django-tables2 table that is being filtered with django-filter . 我有一个django-tables2表,正在使用django-filter进行过滤 I have implemented a scheme based on option D from this great answer . 我从这个很好的答案中实施了一个基于选项D的方案。

However, I am using django-crispy-forms with bootstrap3 for my form rendering. 但是,我正在使用带有bootstrap3的django-crispy-forms进行表单渲染。 This works great until I want to apply a RangeFilter , which spits out two fields (a min and max field). 这非常有用 ,直到我想要应用RangeFilter ,它会吐出两个字段(最小和最大字段)。

The output I get is 我得到的输出是 结果疯狂的价格领域

I would like to control each of those fields manually so that I could PrependedAppendedText them separately. 我想手动控制每个字段,以便我可以单独使用PrependedAppendedText。

Any ideas? 有任何想法吗?

views.py 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 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 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 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)

I had a similar problem after overriding the DateRangeFilter and got around it by amending the widget output to have a div wrapper around it with the form-inline class with the amended bit in def format_output() at the end of the widget class. 覆盖DateRangeFilter之后我遇到了类似的问题,并通过修改窗口小部件输出来绕过它,使用form-inline类,并在widget类的末尾使用def format_output()中的修改位来绕过它。

Screenshot at https://docs.google.com/file/d/0BwIBq4D09D0RaDZGTWhCWnJaZU0 (reputation won't let me post images yet!) 截图https://docs.google.com/file/d/0BwIBq4D09D0RaDZGTWhCWnJaZU0 (声望不允许我发布图片!)

My full code is below (originally taken from https://groups.google.com/d/msg/django-filter/lbi_B4zYq4M/37s63u0WrncJ ) 我的完整代码如下(最初来自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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM