问题
I have a Form
instance with a single IntegerField
.
The IntegerField renders to HTML as an <input>
with type="text"
and data gets POSTed back from an HTML form as a text string. However the form will not validate if the posted data has a string value for the IntegerField (passed in via a dict in the data parameter).
Here's a toy example:
from wtforms import validators, Form, IntegerField
class TestForm(Form):
num = IntegerField('How Many?', [validators.NumberRange(min=1, max=100)])
test_form1 = TestForm()
print("HTML Render 1: %s" % test_form1.num())
data_in = {'num': '66'} # Note '66' is a string as would be POSTed
test_form2 = TestForm(data=data_in)
print("HTML Render 2: %s" % test_form2.num())
print(" Validate: %s" % test_form2.validate())
print(" Errors: %s" % test_form2.errors)
The output is:
HTML Render 1: <input id="num" name="num" type="text" value="">
HTML Render 2: <input id="num" name="num" type="text" value="66">
Validate: False
Errors: {'num': [u'Number must be between 1 and 100.']}
The docstring for IntegerField says:
IntegerField(Field): A text field, except all input is coerced to an integer
How can I coerce a str
into an int
such that this form will pass validation?
回答1:
This is from one of the WTForms devs:
Fields only coerce form data, they don't coerce object data, this lets people use objects >"like an int" and still have them work without the value being clobbered. It's your >responsibility to pass correct datatypes to object/kwargs data.
And from the docs:
process_formdata(valuelist) Process data received over the wire from a form.
This will be called during form construction with data supplied through the formdata argument.
Parameter: valuelist – A list of strings to process.
In your example the process_formdata
method on IntegerField
will never be called
You are passing in a str
and this will not be coerced because you are supplying it as the data
keyword argument. The data
keyword argument signifies exactly the data you want to validate without coercion. Because '66'
is still a str
the validators won't let it pass.
The formdata
keyword argument indicates the data coming in off the wire. This will go through the field's coercion process. There is only one catch, it only accepts MultiDict
like objects. If you look at the example below I've used the webob MutliDict
but there is also one supplied in the Werkzeug library. If you wrap a regular python dictionary in a MultiDict
and supply it as the formdata
keyword your form will validate as expected.
from wtforms import validators, Form, IntegerField
from webob.multidict import MultiDict
class TestForm(Form):
num = IntegerField('How Many?', [validators.NumberRange(min=1, max=100)])
data_in = {'num': '66'} # Note '66' is a string as would be POSTed
test_form2 = TestForm(formdata=MultiDict(data_in))
print("HTML Render 2: %s" % test_form2.num())
print(" Validate: %s" % test_form2.validate())
print(" Errors: %s" % test_form2.errors)
HTML Render 2: <input id="num" name="num" type="text" value="66">
Validate: True
Errors: {}
来源:https://stackoverflow.com/questions/22585652/wtforms-integerfield-skips-coercion-on-a-string-value