WTForms create variable number of fields

前端 未结 3 640
执笔经年
执笔经年 2021-02-05 17:18

How I would dynamically create a few form fields with different questions, but the same answers?

from wtforms import Form, RadioField
from wtforms.validators imp         


        
相关标签:
3条回答
  • 2021-02-05 17:19

    You're almost there:

    CHOICES = [('yes', 'Yes'), ('no', 'No')]
    
    class VariableForm(Form):
    
        def __new__(cls, questions, **kwargs):
            for index, question in enumerate(questions):
                field_name = "question_{}".format(index)
                field = RadioField(question,
                                      validators=[Required()],
                                      choices=CHOICES)
                setattr(cls, field_name, field)
            return super(VariableForm, cls).__new__(cls, **kwargs)
    
    0 讨论(0)
  • In my case, I used a csv and imported it using pandas.

    So, this solution allows you to even use different answers if required.

    data=pd.read_csv("./temp.csv")
    
    class UserForm(Form):
        for i in data:
            if data[i][0] == 'textbox':
                formElement='TextField("%s",validators=[validators.required()], default="please add content")' %(i)
    
            elif data[i][0] == 'radio':
                choice = list(data[i][1:].dropna().unique().tolist())
                choiceStr=''
                for k in choice:
                   choiceStr +="('"+k+"','"+k+"'),"
                
                formElement = 'RadioField("%s",validators=[validators.required()],choices=[%s], default="%s")' %(i,choiceStr, choice[0])
    
            elif data[i][0] == 'dropdown':
                choice = list(data[i][1:].dropna().unique().tolist())
                # choice.remove('X')
                choiceStr=''
                for k in choice:
                   choiceStr +="('"+k+"','"+k+"'),"
                
                formElement = 'SelectField("%s",validators=[validators.required()],choices=[%s])' %(i,choiceStr)
    
    
            exec("%s=%s" % (i,formElement))
    
    
    0 讨论(0)
  • 2021-02-05 17:43

    It was in the docs all along.

    def my_view():
        class F(MyBaseForm):
            pass
    
        F.username = TextField('username')
        for name in iterate_some_model_dynamically():
            setattr(F, name, TextField(name.title()))
    
        form = F(request.POST, ...)
        # do view stuff
    

    What I didn't realize is that the class attributes must be set before any instantiation occurs. The clarity comes from this bitbucket comment:

    This is not a bug, it is by design. There are a lot of problems with adding fields to instantiated forms - For example, data comes in through the Form constructor.

    If you reread the thread you link, you'll notice you need to derive the class, add fields to that, and then instantiate the new class. Typically you'll do this inside your view handler.

    0 讨论(0)
提交回复
热议问题