5
votes

I'm using wtforms, and I need to create a something that will generate a form definition based off information in a database; dynamic form creation. I'm getting a sense of what needs to be done and I've just started. I can create forms and use them with wtforms/flask but defining forms from data that will vary slightly from form to form is currently beyond my current skill level.

Has anyone done this and have some input to offer? Somewhat a vague question, no actual code yet. I haven't found any examples, but it is not impossible to do.

mass of variable data to be used in a form --> wtforms ---> form on webpage

EDIT:

So, a 'for example' we can use surveys. A survey consists of several SQLAlcehmy models. A survey is a model with any number of associated questions models(questions belong to surveys and it gets complicated for say, multiple choice questions). To simplify let's use simple json/dict pseudo code for:

{survey:"Number One",
    questions:{
        question:{type:truefalse, field:"Is this true or false"},
        question:{type:truefalse, field:"Is this true or false"},
        question:{type:text, field:"Place your X here"}
     } 
 }

{survey:"Number Two",
    questions:{
        question:{type:text, field:"Answer the question"},
        question:{type:truefalse, field:"Is this true or false"},
        question:{type:text, field:"Place your email address here"}
     } 
 }

Imagine instead of this, several hundred of varying lengths with 5+ field types. How to use WTForms to manage forms for this, or do I even need to use wtforms? I can define static forms as I need them, but not dynamically, yet.

As an aside I've done something like this in rails with simpleform but as I'm working in Python atm (on something different, I'm using the survey thing as an example, but the question/field/answer thing abstracts across a many types of inputs I've needed).

So yes it is possible I'll need to build some sort of factory, doing it will take me some time e.g.:

http://wtforms.simplecodes.com/docs/1.0.2/specific_problems.html

https://groups.google.com/forum/?fromgroups=#!topic/wtforms/cJl3aqzZieA

2
You could have a look at the extensions that are shipped with wtforms. E.G. the SQLAlchemy Extension can generate a form from the model bitbucket.org/simplecodes/wtforms/src/113994790508/wtforms/ext/… Your question is a bit vague. Could you give a practical example what and when something in the form has to change? - Smoe
It is a series of models that have other models belonging to them....a thing survey has any number of questions, each question has any number of spaces for answers; i.e. user generated forms for questions/answers in a survey format. - blueblank
Ok, I believe the model_form method in the link i posted above, is what you're looking for. It generates a Form from a given model on the fly. Additionaly, Flask-Admin is imo a good example how you can use it to actually render the form github.com/mrjoes/flask-admin/blob/master/flask_admin/templates/… - Smoe
The first link is somewhat along the path...I need to create a form from an instance of class and instances of classes that belong to that specific instance(e.g. a form for an instance of a survey class with ten t/f questions vs a form for instance of a survey class with 100 text field input questions) and this doesn't seem to accomodate instances unless I need to build some sort of dynamic per survey class that subclasses those hmmm - blueblank
If you feel that this is "currently beyond your skill", perhaps you can ask a question that gets you in the right direction that is within your skill? Perhaps how to create and use a dynamically generated form using wtform (with just junk data in lists/dicts)? Once you're comfortable with that, you can tie in the use of the database as the source for your data. - Mark Hildreth

2 Answers

4
votes

Simply add the appropriate fields to the base form at run time. Here's a sketch of how you might do it (albeit much simplified):

class BaseSurveyForm(Form):
    # define your base fields here


def show_survey(survey_id):
    survey_information = get_survey_info(survey_id)

    class SurveyInstance(BaseSurveyForm):
        pass

    for question in survey_information:
        field = generate_field_for_question(question)
        setattr(SurveyInstanceForm, question.backend_name, field)

    form = SurveyInstanceForm(request.form)

    # Do whatever you need to with form here


def generate_field_for_question(question):
    if question.type == "truefalse":
        return BooleanField(question.text)
    elif question.type == "date":
        return DateField(question.text)
    else:
        return TextField(question.text)
0
votes
class BaseForm(Form):
    @classmethod
    def append_field(cls, name, field):
        setattr(cls, name, field)
        return cls

from forms import TestForm
form = TestForm.append_field("do_you_want_fries_with_that",BooleanField('fries'))(obj=db_populate_object)

I use the extended class BaseForm for all my forms and have a convenient append_field function on class.

Returns the class with the field appended, since instances (of Form fields) can't append fields.