简体   繁体   中英

Python WTForms: How to dynamically set options of a SelectField in FieldList of FormFields?

I am currently trying to use WTForms 's FieldList and FormField enclosures to allow users to add a custom subset of locations with corresponding coverage amounts.

The form presents a user with some standard inputs and then initializes with a single set of fields (FormField) each with a location select input and a coverage amount input.

Javascript allows the user to add or remove additional location coverage field sets as needed to reflect the accurate document information.

The Problem: As a workaround, I have been setting the location options by passing a template variable in the form handler's GET request and manually creating my own form fields. This isn't updating the actual WTForms location field choices though, so when I submit the form an exception is raised for the location field ('Not a valid choice').

How can I dynamically add location choices to the location field of the LocationForm when I instantiate MyForm ?

This is basically how my code looks:

Note: I have omitted the code that creates a locations template variable in the GET request since that is not the desired design. I want to be more in line with the intended WTForms methodology :

class LocationForm(Form):
    location = SelectField('Location', [], choices=[])
    coverage = FloatField('Coverage', [])

class MyForm(BaseForm):
    # other fields omitted for brevity
    location_coverage = FieldList(FormField(LocationForm), [], min_entries=1)

class AddDocument(BaseHandler):

    def get(self):
        params = {
           "cid": cid
        }
        return self.render_template("form.html", **params)

    def post(self):
        cid = self.request.get('cid')
        if not self.form.validate():
            return self.get()
        company_key = ndb.Key('Company', cid)
        doc = Document(parent=company_key)
        self.form.populate_obj(doc)
        doc.put()
        params = { 
            "cid": 
        }
        return self.redirect_to('view_company', **params)

    @webapp2.cached_property
    def form(self):
        f = MyForm(self)

        # HERE is where I would normally do something like:
        # company = ndb.Key('Company', int(self.request.get('cid')))
        # locations = ndb.Location.query(ancestor=company).fetch() 
        # f.field_name.choices = [(loc.key, loc.name) for loc in locations]
        # but this doesn't work with Select Fields enclosed in 
        # FormFields and FieldLists.

        return f

Edit:

I created a solution but this isn't the answer I am looking for. In my case, I simply changed the LocationForm.location form field from a SelectField to a StringField. Doing this bypasses the validation of the select field choices and allows the form to submit. This is not ideal as it is not the intended design, but if anyone can steer me toward a more proper way to use WTForms in this particular scenario I would greatly appreciate it.

If your BaseForm class populates the form from the post data on instantiation, you should see the nested forms populated at the point where you'd normally add the choices into a SelectField directly on the form.

Therefore something like:

for entry in f.location_coverage.entries:
    entry.location.choices = [(loc.key, loc.name) for loc in locations]

Should populate the choices into each subform select field.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM