在Django中处理过滤器表单以及其他get参数

时间:2018-08-30 10:28:04

标签: python django django-forms django-tables2

我有一个django表单,其中包含2个必填字段和一些可选字段,用于过滤视图中显示的数据。

此视图使用了一些GET参数,而不是用于过滤器表单的参数,我正在从form = MyFilterForm(request.GET or None)之类初始化过滤器[请参见下面的代码(1)]。

我发现什么时候第一次加载我的视图,并且没有GET参数,因为request.GET是错误的,所以该形式可以正常工作,因此表单不受约束(因此我们使用初始值) (用于必填字段)。如果使用了过滤器表单,那么request.GET将被填充以表单参数,并且一切都将再次正常运行。但是,如果我的其他GET个参数之一(即用于对结果数据表进行排序的一个参数)在未使用过滤器形式的情况下通过了,那么request.GET是正确的,但没有任何对应的参数表单,因此表单被绑定,并且由于未为我的必填字段赋予值,错误被视为无效。

这里应该发生的是,应该对数据表进行排序,并且表单应该继续使用初始(“默认”)值,就像第一次加载时一样。

这有点棘手,有些代码可能会更清楚...

我已经在Google上进行了广泛的搜索,因为这似乎是其他人也必须解决的问题,但是没有找到任何运气。

我正在使用django-tables2向用户显示表中的数据,但是这个问题更多地围绕表单,您需要了解的关于表的唯一一件事就是它允许用户对表进行排序通过单击表标题在表中显示的数据-然后将GET参数添加到带有列的请求中,以按IE ?sort=start_date进行排序。

class MyFilterForm(forms.Form):
    date_from = DateTimeField(required=True)
    date_to = DateTimeField(required=True)
    user = ModelChoiceField(required=False, queryset=User.objects.all())

    def __init__(self, *args, **kwargs):
        super(MyFilterForm, self).__init__(*args, **kwargs)
        # dates in correct timezone and at start/end of day
        # initial values set in __init__ so that they aren't fixed at import time
        week_start, week_end = get_start_end_week(timezone.now())
        self.fields['date_from'].initial = week_start
        self.fields['date_to'].initial = week_end

在我看来

import django-tables2 as tables


@login_required
def view_with_filter_form_and_table(request):
    form = MyFilterForm(request.GET or None)  # (1) The form gets bound when the table is sorted here as request.GET is truthy
    if form.is_bound and form.is_valid():
        date_from = self.cleaned_data['date_from']
        date_to = self.cleaned_data['date_to']
    else:
        # use defaults if not bound or not valid
        date_from = form.fields['date_from'].initial
        date_to = form.fields['date_to'].initial
    user = form.cleaned_data.get('user') if form.is_bound else None

    query = Action.objects.all()

    if date_from:
        query = query.filter(date__gte=date_from)
    if date_to:
        query = query.filter(date__lte=date_to)
    if user:
        query = query.filter(user=user)

    table = MyTable(query)
    tables.RequestConfig(request, paginate=False).configure(table)

    return render(request, 'my_form_and_table.html', {'form': form, 'table': table})

我考虑过的

在绑定到表单之前,检查所有必填字段都在request.GET中。除了有点代码味道之外,因为我需要实例化一个未绑定的表单以遍历所有字段,并检查所需的字段是否在request.GET中,甚至不知道我是否应该实例化绑定的表单。这里的问题是,如果编辑了表单,并且用户将必填字段之一设置为空,我仍然希望显示验证错误,也就是This field is required.

1 个答案:

答案 0 :(得分:0)

我目前正在通过在标记为(1)的代码下添加以下代码来解决此问题,但是如果有更干净的解决方案,我会喜欢的。

for name, field in form.fields.items():
    if field.required and name not in request.GET:
        form = MyFilterForm(None)  # unbound form
        break