wtforms hidden field value

SkinnyPete63 picture SkinnyPete63 · Nov 29, 2012 · Viewed 41.7k times · Source

I am using WTForms, and I have a problem with hidden fields not returning values, whereas the docs say they should. Here's a simple example:

forms.py:

from wtforms import (Form, TextField, HiddenField)

class TestForm(Form):
    fld1 = HiddenField("Field 1")
    fld2 = TextField("Field 2")

experiment.html:

{% from "_formshelper.html" import render_field %}
<html>
    <body>
        <table>
        <form method=post action="/exp">
            {% for field in form %}
                {{ render_field(field) }}
            {% endfor %}
            <input type=submit value="Post">
        </form>
        </table>        
    </body>
</html>

(render_field just puts the label, field and errors in td tags)

experiment.py:

from flask import Flask, request, render_template

from templates.forms import *
from introspection import *

app = Flask(\__name__)                  
app.config.from_object(\__name__)
db_session = loadSession()

@app.route('/exp', methods=['POST', 'GET'])
def terms():
    mydata = db_session.query(Peter).one()
    form = TestForm(request.form, mydata)
    if request.method == 'POST' and form.validate():
        return str(form.data)
    return render_template('experiment.html', form = form)

if __name__ == '__main__':
    app.run(debug = True)  

mydata returns the only row from a table that has 2 fields, fld1 and fld2. fld1 is an integer autoincrement field. The form is populated with that data, so if I run experiment.py, when I submit the form I get:

{'fld2': u'blah blah blah', 'fld1': u'1'}

But if I change fld1 to HiddenField, when I hit submit, I get: {'fld2': u'blah blah blah', 'fld1': u''}

What am I doing wrong?

Answer

Rachel Sanders picture Rachel Sanders · Nov 29, 2012

I suspect your hidden field is either (1) not getting a value set, or (2) the render_field macro isn't building it correctly. If I had to bet, I'd say your "mydata" object doesn't have the values you expect.

I stripped your code down to the bare minimum, and this works for me. Note I am explicitly giving a value to both fields:

from flask import Flask, render_template, request
from wtforms import Form, TextField, HiddenField

app = Flask(__name__)

class TestForm(Form):
  fld1 = HiddenField("Field 1")
  fld2 = TextField("Field 2")


@app.route('/', methods=["POST", "GET"])
def index():
  form = TestForm(request.values, fld1="foo", fld2="bar")
  if request.method == 'POST' and form.validate():
    return str(form.data)

  return render_template('experiment.html', form = form)

if __name__ == '__main__':
  app.run()

and

<html>
<body>
<table>
    <form method=post action="/exp">
        {% for field in form %}
            {{field}}
        {% endfor %}
        <input type=submit value="Post">
    </form>
</table>
</body>
</html>

This gives me {'fld2': u'bar', 'fld1': u'foo'} as I would expect.

Check that mydata has an attribute "fld1" and it has a value. I might set it explicitly like form = TestForm(request.values, obj=mydata) - it doesn't look like WTForms would care, but I've gotten burned by it being weirdly picky sometimes.

If that doesn't work for you, come back and post your HTML and what values mydata has.