尝试在动态 WTForm 字段中插入空白选项
Trying to insert blank option in dynamic WTForm field
我试图根据我在 SOF here 上找到的结果在现有的工作动态字段(客户)中添加一个空白选项,但是出现错误。
错误是ValueError: invalid literal for int() with base 10: ''.
如有必要,我可以提供完整的回溯。
这是表格 - 如您所见,动态字段是客户:
class FilterWorkorderForm(FlaskForm):
id = IntegerField('id', validators=[Optional()])
date = DateField('Date', validators=[Optional()])
customer = SelectField('Customer', coerce=int, validators=[Optional()])
customer_po = StringField('Customer PO', validators=[Optional()])
requested_by = StringField('Requested By', validators=[Optional()])
work_description = StringField('Work Description', validators=[Optional()])
status = SelectField('Status', choices=[('Quote', 'Quote'), ('Pending', 'Pending'), ('WIP', 'WIP'), ('Complete', 'Complete'), ('TBI', 'TBI'), ('Invoiced', 'Invoiced'), ('VOID', 'VOID')])
路线如下:
@app.route('/reports/filter_workorder', methods=['GET', 'POST'])
@login_required
def filter_workorder():
results = None
form = FilterWorkorderForm()
form.customer.choices = [(cus.id, cus.company_name) for cus in Company.query.order_by('id')]
### LINE CAUSING ERROR ### form.customer.choices.insert(0, ("", "")) ### LINE CAUSING ERROR ###
if request.method == 'POST':
if form.validate_on_submit():
try:
customer_id = form.customer.data
customer = Company.query.filter_by(id = customer_id).first_or_404()
customer_name = customer.company_name
filter_data = {'id' : form.id.data, 'date' : form.date.data, 'customer_po' : form.customer_po.data, 'customer' : customer_name,
'work_description' : form.work_description.data, 'status' : form.status.data}
filter_data = {key: value for (key, value) in filter_data.items() if value}
results = Workorder.query.filter_by(**filter_data).all()
except Exception as e:
db.session.rollback()
flash(e)
return render_template('filter_workorder.html', form = form, results = results)
return render_template('filter_workorder.html', form = form)
问题在于使用整数强制转换呈现您的表单,特别是客户字段。
根据 WTForms's documentation on the Select
widget:
The field must provide an iter_choices()
method which the widget will call on rendering; this method must yield tuples of (value, label, selected)
.
如果你看the source code for this method:
def iter_choices(self):
for value, label in self.choices:
yield (value, label, self.coerce(value) == self.data)
此方法中没有针对强制转换失败的异常处理。在您的情况下,self.coerce(value)
作为 int('')
执行,这会导致您遇到 ValueError
异常。
至少有两种解法:
- 移除
coerce
.
使用 sentinel value 例如 0
或 -1
表示没有客户被选中:
form.customer.choices.insert(0, (0, ""))
该值将通过强制转换,但您需要处理该值(以取消设置 "customer" 字段)post 表单处理。
我试图根据我在 SOF here 上找到的结果在现有的工作动态字段(客户)中添加一个空白选项,但是出现错误。
错误是ValueError: invalid literal for int() with base 10: ''.
如有必要,我可以提供完整的回溯。
这是表格 - 如您所见,动态字段是客户:
class FilterWorkorderForm(FlaskForm):
id = IntegerField('id', validators=[Optional()])
date = DateField('Date', validators=[Optional()])
customer = SelectField('Customer', coerce=int, validators=[Optional()])
customer_po = StringField('Customer PO', validators=[Optional()])
requested_by = StringField('Requested By', validators=[Optional()])
work_description = StringField('Work Description', validators=[Optional()])
status = SelectField('Status', choices=[('Quote', 'Quote'), ('Pending', 'Pending'), ('WIP', 'WIP'), ('Complete', 'Complete'), ('TBI', 'TBI'), ('Invoiced', 'Invoiced'), ('VOID', 'VOID')])
路线如下:
@app.route('/reports/filter_workorder', methods=['GET', 'POST'])
@login_required
def filter_workorder():
results = None
form = FilterWorkorderForm()
form.customer.choices = [(cus.id, cus.company_name) for cus in Company.query.order_by('id')]
### LINE CAUSING ERROR ### form.customer.choices.insert(0, ("", "")) ### LINE CAUSING ERROR ###
if request.method == 'POST':
if form.validate_on_submit():
try:
customer_id = form.customer.data
customer = Company.query.filter_by(id = customer_id).first_or_404()
customer_name = customer.company_name
filter_data = {'id' : form.id.data, 'date' : form.date.data, 'customer_po' : form.customer_po.data, 'customer' : customer_name,
'work_description' : form.work_description.data, 'status' : form.status.data}
filter_data = {key: value for (key, value) in filter_data.items() if value}
results = Workorder.query.filter_by(**filter_data).all()
except Exception as e:
db.session.rollback()
flash(e)
return render_template('filter_workorder.html', form = form, results = results)
return render_template('filter_workorder.html', form = form)
问题在于使用整数强制转换呈现您的表单,特别是客户字段。
根据 WTForms's documentation on the Select
widget:
The field must provide an
iter_choices()
method which the widget will call on rendering; this method must yield tuples of(value, label, selected)
.
如果你看the source code for this method:
def iter_choices(self):
for value, label in self.choices:
yield (value, label, self.coerce(value) == self.data)
此方法中没有针对强制转换失败的异常处理。在您的情况下,self.coerce(value)
作为 int('')
执行,这会导致您遇到 ValueError
异常。
至少有两种解法:
- 移除
coerce
. 使用 sentinel value 例如
0
或-1
表示没有客户被选中:form.customer.choices.insert(0, (0, ""))
该值将通过强制转换,但您需要处理该值(以取消设置 "customer" 字段)post 表单处理。