Dynamic choices in wtforms SelectField.

I’ve built a Django app that is used internally at my job. I’m migrating it to Odoo (formerly OpenERP).

One of the things i had to do was move from django forms to wtforms (since Odoo does not supply a forms system)

Now the official wtforms documentation states that in order to provide dynamic forms to a SelectField you have to supply the assign the choices argument at instantiation time (instead of the class definition). This simply would not do for my setup because it is a complicated ‘plugin’-like system. The class that instantiates forms knows knothing about the form definition or where it came from.

A quick Google and Stackoverflow search did not turn up a solution so i dug into the wtforms sourcecode and found out that choices is treated as an iterable. No type checks or anything.

So i simply created a class for my data that implemented the __iter__ method:

from wtforms import Form , SelectField
class RandomChoicesIterable(object):
    def __iter__(self):
        from random import randint
        for i in xrange(0,5):
            pair = (randint(1,100),randint(1,100))
            yield pair

class MyForm(Form):
        randomchoices = SelectField(
            choices = RandomChoicesIterable(),
            label = "Random choices every time!"
            )

Now, you would get your database stuff in the __iter__ method instead of giving random data but this is only an example.

For example:

>>> form = MyForm()
>>> for field in form:
...    print field
...
<select id="randomchoices" name="randomchoices"><option value="40">9</option><option value="41">15</option><option value="11">6</option><option value="1">95</option><option value="39">33</option></select>
>>> for field in form: print field
...
<select id="randomchoices" name="randomchoices"><option value="82">81</option><option value="43">7</option><option value="97">87</option><option value="100">48</option><option value="85">59</option></select>
>>> for field in form: print field
...
<select id="randomchoices" name="randomchoices"><option value="29">89</option><option value="10">37</option><option value="58">37</option><option value="14">97</option><option value="10">22</option></select>
>>> for field in form: print field
...
<select id="randomchoices" name="randomchoices"><option value="22">18</option><option value="96">92</option><option value="27">81</option><option value="59">94</option><option value="28">42</option></select>
>>> for field in form: print field
...
<select id="randomchoices" name="randomchoices"><option value="17">5</option><option value="73">31</option><option value="21">68</option><option value="82">11</option><option value="81">61</option></select>
>>> for field in form: print field
...
<select id="randomchoices" name="randomchoices"><option value="37">53</option><option value="13">18</option><option value="69">73</option><option value="16">51</option><option value="86">14</option></select>
>>> for field in form: print field
...
<select id="randomchoices" name="randomchoices"><option value="81">42</option><option value="86">50</option><option value="29">71</option><option value="45">74</option><option value="43">35</option></select>

Big Fat Warning

Since this is not the documented method, it might break in future versions of wtforms.