I want to set attributes dynamically to a FlaskForm like this
form = ModelForm(request.form)
file form.py
class ModelForm(FlaskForm):
def __init__(self, postData):
super(ModelForm, self).__init__()
for p in postData:
setattr(ModelForm, p, StringField(p, validators=[InputRequired()]))
But it only work for the second time running, the first time running, it doesn't work.
I really don't understand how python constructor works. As this post, it said because
class A is not fully initialized when you do your setattr(A, p, v) there.
But in other languages, the object have to be created after constructor finished, and it has full class variables, properties declared in the constructor ?
For example, it works and can print a.key. So what's difference there in the flask constructor and this?
class A(object):
def __init__(self):
self.a = 'i am a accessor'
setattr(self, 'key', 'value')
a = A()
print a.a
print a.key
means, when you create your first instance of your class with
form=ModelForm()
, you start adding attributes to the class you are currently instancing from. I don't know, how exactly this works internally in Python. But since you say this only works in the second run, I guess the object is first created with all attributes defined for the class, then__init__
is executed. So the new attributes are added to late.In other words: Your are trying to change the class definition after you already created an instance of it. You need to add all your attributes, before you instantiate.
Now what you need to do is: first define the class without any dynamic fields. Then, after the class definition, you add the loop with your dynamic fields.
Or if you need to add some other stuff in class definition:
And then, somewhere in your view function, you can use
form = ModelForm(request.form)
as usual.Usually you know what fields you need beforehand. The form just answers on what it got from the GET request. So this should be fine. But maybe you added some more fields with some JS on client side, which the server does not know about (yet). In that case you might try to put the class definition into the local scope of the view function which handles the POST request.