在跨 FormFields 的不同 FieldLists 验证表单时如何处理错误消息?
How to handle error messages when validating a form across different FieldLists of FormFields?
我有一个包含(在其他字段中)2 个字段列表的表单。每个 FieldList 都是 FormFields 的列表。在每个 FieldList 中,表单都代表项目。一个实地列表用于已取消预算的项目,另一个列表用于将成为该预算接受者的项目。这是一种动态形式;可以有任意数量的解除分配或分配。整个表单中会有很多验证,但我无法工作的一个简单案例是确保没有项目在表单中出现两次(也就是说,在两个列表中,项目 ID 必须是唯一的)。我可以对此进行测试并识别这种情况何时发生,但我无法将错误消息与有问题的项目 ID 相关联。
我的表格 类 的简化版本是:
class AllocationForm(Form):
project_id(StringField, label='Project ID')
... details about amount being allocated here
class DeallocationForm(Form):
project_id(StringField, label='Project ID')
...details about amount being deallocated here
class RequestForm(FlaskForm):
def validate(self):
project_id_seen = {}
project_list = [a for a in self.allocations] + [d for d in self.deallocations]
for formfield in project_list:
if project_id_seen.get(formfield.data.get('project_id')) is None:
project_id_seen[formfield.data.get('project_id')] = 1
else:
# *** Here's where I'm having an issue ***
somethingsomethingsomething['project_id'] = 'A project ID cannot appear more than once in a request'
return False
# other form validations happen here
if not FlaskForm.validate(self):
return False
allocations = FieldList(FormField(AllocationForm))
deallocations = FieldList(FormField(DeallocationForm))
如您所见,我重写了 RequestForm
的 validate
方法。我在 else 子句中 return False
的地方,我想将一条错误消息与相关项目 ID 相关联,以便我可以在重新呈现表单时显示它,但我难以访问子表单中的特定 project_id
字段。有什么想法吗?
编辑:我想到另一种方法可能是将验证器放在 AllocationForm
和 DeallocationForm
类 中的项目 ID 字段上,而不是 RequestForm
。这是一种更可行的方法吗?将错误消息与字段相关联会更容易,但是 AllocationForm
中的验证器如何访问 DeallocationForm
中的项目 ID,反之亦然?
你使用 validate
的方法对我来说很有意义,我认为你接近实现你的目标。
为了能够将错误消息分配给一个字段,您可以临时存储必要的字段,然后在需要时向相应字段的错误消息元组中添加一个条目。
from collections import defaultdict
class AllocationForm(Form):
project_id = StringField('Project ID')
# ...
class DeallocationForm(Form):
project_id = StringField('Project ID')
# ...
class RequestForm(FlaskForm):
allocations = FieldList(FormField(AllocationForm))
deallocations = FieldList(FormField(DeallocationForm))
def validate(self):
data_fields = defaultdict(list)
for field in (self.allocations, self.deallocations):
for form in field:
if form.project_id.data:
data_fields[form.project_id.data].append(form.project_id)
success = True
for data,fields in data_fields.items():
if len(fields) > 1:
for field in fields:
msg = 'A project ID cannot appear more than once in a request'
field.errors += (msg,)
success = False
return success and super().validate()
我有一个包含(在其他字段中)2 个字段列表的表单。每个 FieldList 都是 FormFields 的列表。在每个 FieldList 中,表单都代表项目。一个实地列表用于已取消预算的项目,另一个列表用于将成为该预算接受者的项目。这是一种动态形式;可以有任意数量的解除分配或分配。整个表单中会有很多验证,但我无法工作的一个简单案例是确保没有项目在表单中出现两次(也就是说,在两个列表中,项目 ID 必须是唯一的)。我可以对此进行测试并识别这种情况何时发生,但我无法将错误消息与有问题的项目 ID 相关联。
我的表格 类 的简化版本是:
class AllocationForm(Form):
project_id(StringField, label='Project ID')
... details about amount being allocated here
class DeallocationForm(Form):
project_id(StringField, label='Project ID')
...details about amount being deallocated here
class RequestForm(FlaskForm):
def validate(self):
project_id_seen = {}
project_list = [a for a in self.allocations] + [d for d in self.deallocations]
for formfield in project_list:
if project_id_seen.get(formfield.data.get('project_id')) is None:
project_id_seen[formfield.data.get('project_id')] = 1
else:
# *** Here's where I'm having an issue ***
somethingsomethingsomething['project_id'] = 'A project ID cannot appear more than once in a request'
return False
# other form validations happen here
if not FlaskForm.validate(self):
return False
allocations = FieldList(FormField(AllocationForm))
deallocations = FieldList(FormField(DeallocationForm))
如您所见,我重写了 RequestForm
的 validate
方法。我在 else 子句中 return False
的地方,我想将一条错误消息与相关项目 ID 相关联,以便我可以在重新呈现表单时显示它,但我难以访问子表单中的特定 project_id
字段。有什么想法吗?
编辑:我想到另一种方法可能是将验证器放在 AllocationForm
和 DeallocationForm
类 中的项目 ID 字段上,而不是 RequestForm
。这是一种更可行的方法吗?将错误消息与字段相关联会更容易,但是 AllocationForm
中的验证器如何访问 DeallocationForm
中的项目 ID,反之亦然?
你使用 validate
的方法对我来说很有意义,我认为你接近实现你的目标。
为了能够将错误消息分配给一个字段,您可以临时存储必要的字段,然后在需要时向相应字段的错误消息元组中添加一个条目。
from collections import defaultdict
class AllocationForm(Form):
project_id = StringField('Project ID')
# ...
class DeallocationForm(Form):
project_id = StringField('Project ID')
# ...
class RequestForm(FlaskForm):
allocations = FieldList(FormField(AllocationForm))
deallocations = FieldList(FormField(DeallocationForm))
def validate(self):
data_fields = defaultdict(list)
for field in (self.allocations, self.deallocations):
for form in field:
if form.project_id.data:
data_fields[form.project_id.data].append(form.project_id)
success = True
for data,fields in data_fields.items():
if len(fields) > 1:
for field in fields:
msg = 'A project ID cannot appear more than once in a request'
field.errors += (msg,)
success = False
return success and super().validate()