3

I'm working on an app that uses WTForms in combination with an templating engine.

The forms that are being shown to the user are not pre defined, but can be dynamically configured by the admin. So the WTForm needs to be able to dynamically add fields, I have achieved this by specifying this subclass of Form (as suggested by):

class DynamicForm(Form):
@classmethod
def append_field(cls, name, field):
    setattr(cls, name, field)
    return cls

This works fine, but it seems that via this method you cannot populate the fields through Form(obj=values_here). This is my current instantiation of the Form subclass mentioned above:

values = {}
values['password'] = 'Password123'

form = DynamicForm(obj=values)
form.append_field("password", PasswordField('password'))

So this won't work, and this makes sense when you consider the field to be added after the Form's init has been called. So I have been searching for a way to also assign the value of a field dynamically, but I haven't had any luck so far.

Does anyone know of a way to set the password field in the example to a certain value? Would be greatly appreciated.

Community
  • 1
  • 1
Karsten
  • 109
  • 10

2 Answers2

2

Try this:

>>> form = DynamicForm().append_field('password',
                                      PasswordField('password'))(
                                          password="Password123")
>>> form.data
{'password': 'Password123'}
dkol
  • 1,421
  • 1
  • 11
  • 19
0

The solution mentioned here by dkol works like a charm, but it does require you to actually know the name of the field (in other words, it can't be computed). This is because the named parameter's key which you're passing along in (password="Password123") can't be an expression, or an variable. Meaning that an for loop like this won't work:

form = DynamicForm()

for field in fields:
    form = form.append_field(field.label, StringField(field.label))(field.label=field.value)

So after some fiddling around with the former solution provided by dkol, I came up with this:

form = DynamicForm()

class formReferenceObject:
    pass

for field in fields:
    form = form.append_field(field.label, StringField(field.label))
    setattr(formReferenceObject, field.label, field.value)

form = form(obj=formReference)

This solution may require a bit more code, but is still really readable and is very flexible. So when using an for loop / an computed <input /> name, this will help you.

Karsten
  • 109
  • 10