首页 > 解决方案 > 如何使用动态更新的 Choicefield 验证表单集?

问题描述

我正在使用formset_factory在我的页面上管理几个相同的表单。在每种形式中,都有一对链式下拉菜单。DropdownA 有一个 onchange 事件,它请求 dropdownB (AJAX) 的选项。这一切都很好,但是当我通过 POST 请求提交表单时,它们都未通过forms.is_valid()检查。打印提交的表单集的错误揭示了原因:

[{'DropdownB ': ['Select a valid choice. Like is not one of the available choices.']}, {'DropdownB ': ['Select a valid choice. < is not one of the available choices.']}]

有两个错误,每个表格一个。他们都抱怨为 DropdownB 发送的选择不是可用的选项之一(恭敬地“喜欢”和“<”)。

现在,因为我只想根据 DropdownA 选择的内容用某些选项填充 DropdownB,所以我特意用 0 个选项定义了 DropdownB(一个选择字段)。

DropdownB = ()
DropdownB = forms.ChoiceField(choices=op_choices, required=False)

如何根据 DropdownA 的值向服务器指定有效选择是什么?

我试图在上面的摘要中简化这个问题,但是如果你想要表格的完整代码,你可以去:

class UnifiedSingleSearchBar(forms.Form):
# Dict to categorize field types
type_dict = {
    'DateField': 'Numeric',
    'DateTimeField': 'Numeric',
    'AutoField': 'Numeric',
    'CharField': 'String',
    'BooleanField': 'Bool',
}
operation_dict = {'Numeric':
                      (
                          ('>', '>'),
                          ('>=', '>='),
                          ('<', '<'),
                          ('<=', '<='),
                          ('=', '='),
                          ('>-<', 'Between'),
                          ('0', 'IS null'),
                          ('1', 'IS NOT null'),
                      ),
                    'String':
                        (
                            ('Like', 'Like'),
                            ('Is', 'Is')
                        ),
                    'Bool':
                        (
                            ('True', 'True'),
                            ('False', 'False')
                        )
                  }
searchabel_field_choices = ()
# To create the "field" dropdown, we loop through every field in the model and note its type.
for field in Mymodel._meta.fields:
    tuple = (
        (field.name, field.name),  # signifies a nested tuple
    )
    searchabel_field_choices = searchabel_field_choices + tuple
searchabel_field_choices = searchabel_field_choices + (('', '--------'),)
shared_attrs = {
    'autocomplete': 'off',
    'class': 'form-control datetimepicker-input',
}
searchable_field = forms.ChoiceField(choices=searchabel_field_choices, required=False)
op_choices = ()  # Should always start with an empty operations list since field has not yet been chosen
operation = forms.ChoiceField(choices=op_choices, required=False)

# 2 is usually only ever used if a range is being specified
# Numeric
date1 = forms.DateField(required=False, widget=DatePicker(attrs=shared_attrs))
date2 = forms.DateField(required=False, widget=DatePicker(attrs=shared_attrs))
datetime1 = forms.DateTimeField(required=False, widget=DateTimePicker(attrs=shared_attrs))
datetime2 = forms.DateTimeField(required=False, widget=DateTimePicker(attrs=shared_attrs))
integer = forms.IntegerField(required=False)
# Bool
bool = forms.BooleanField(required=False)
# String
string = forms.CharField(required=False)

标签: djangodjango-forms

解决方案


答案在这里解决了我的问题。每次遍历表单集中的表单时,您都会读取请求中为该表单指定的 DropdownA 中的值,并使用该信息为 DropdownB 设置有效选择,再次根据该特定表单。

编辑:为那些仍然需要澄清的人添加额外的信息。

因此,在从客户端收到表单后,在您验证它们之前的某个地方,forms.is_valid()您将循环遍历它们,检查为 dropdownA 指定的值并更新 dropdownB 的选项。

很可能您正在使用数据库中的值填充下拉列表,因此这通常会使这些检查和更新变得容易。首先,您将查看客户端为 dropdownA 指定的值是否是数据库的有效成员(必须确保没有发生有趣的事情) model1_record = model1.objects.get(<dropdownA val>) 然后假设在数据库中找到 dropdownA,您可能正在尝试将有效的 dropdownB 选项限制为与您已识别的记录相关联的记录。您可以通过像这样更新 dropdownB 的查询集来做到这一点form.fields['dropdownB'].queryset = model2.objects.filter(model1FK=model1_record)

在对所有表单执行此操作之后,现在您可以调用forms.is_valid()并且您不应该收到无效选择错误(好吧,如果该 ddB 确实与 ddA 相关)。


推荐阅读