在 Django 中处理过滤器表单和其他获取参数

Handling a filter form along with other get parameters in Django

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

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

我发现当我的视图第一次加载时没有 GET 参数这工作正常因为 request.GET 是假的所以表单没有被绑定(因此我们使用必填字段的初始值)。如果使用过滤器表单,则 request.GET 将填充表单参数,并且一切正常。但是,如果我的其他 GET 参数之一(即用于对结果数据 table 进行排序的参数)在没有使用过滤器表单的情况下通过,则 request.GET 是真实的但没有任何与表单对应的参数,因此表单被绑定并且错误无效,因为我的必填字段没有被赋予值。

这里应该发生的是数据 table 应该排序并且表单应该继续使用初始 ('default') 值,就像第一次加载时一样。

解释起来有点棘手,用一些代码可能会更清楚...

我在谷歌上进行了大量搜索,因为这感觉就像是其他人也一定遇到的问题,但没有找到任何东西。

我正在使用 django-tables2 为用户呈现 table 中的数据,但这个问题更多的是围绕表单,您唯一需要了解的是 table 是它允许用户通过单击 table 标题对 table 中显示的数据进行排序 - 然后将 GET 参数添加到请求中,其中包含按 I.E ?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) 的代码下添加以下代码来解决此问题,但如果有更简洁的解决方案,我会很高兴。

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