WTForms: FieldList of FormField can't load nested data
Asked Answered
P

3

8

I have a custom field inside a FormField inside a FieldList: locations

class LocationForm(Form):
    id = HiddenField('id')
    title = StringField(_l('Title'), [Required()])
    location = CoordinatesField(_l('Coordinates'))

class ProjectForm(Form):
    title = StringField(_l('Title'))
    manager = StringField(_l('Manager'))
    description = StringField(_l('Description'))
    locations = FieldList(FormField(LocationForm), min_entries=1)

This form when submited is saved to an object like this:

document = {
    'title': unicode,
    'description': unicode,
    'manager': unicode,
    'locations': [{
        'id': uuid.UUID,
        'title': unicode,
        'location': {'coordinates':[float], 'text':unicode}
        }],
    }

When I try to load the data in to the form for a GET handler, everything but the locations loads fine:

f = form(MultiDict(document))
f.locations.data
>> {'id':'','title':'','location':''}

I did some debugging and found that WTForms while loading the document's data in to the form searches for 'locations-0-location' but MultiDict() but that keys doesn't exists. MultiDict doesn't convert a list of dictionaries to the key 'locations-i-...'.

What is the right way to make a WTForm for such a nested data structure?

Popovich answered 8/8, 2014 at 12:1 Comment(3)
Having the same problem, did you find a solution?Analisaanalise
I too am running into the same issue. Still searching..Cailly
I might have found out, check answer belowAnalisaanalise
R
4

with WTFORMS 2.1

the data:

document = {
    'title': unicode,
    'description': unicode,
    'manager': unicode,
    'locations': [{
        'id': uuid.UUID,
        'title': unicode,
        'location': {'coordinates':[float], 'text':unicode}
        }],
    }

you set the data structure with WTFORMS:

class LocationForm(Form):
    id = HiddenField('id')
    title = StringField(_l('Title'), [Required()])
    location = CoordinatesField(_l('Coordinates'))

class ProjectForm(Form):
    title = StringField(_l('Title'))
    manager = StringField(_l('Manager'))
    description = StringField(_l('Description'))
    locations = FieldList(FormField(LocationForm), min_entries=1)

try this:

f = ProjectForm()
f.process(data=document)
f.locations.data
Roden answered 30/4, 2018 at 7:26 Comment(0)
U
1

I had the same problem and was able to sort it by flattening the list to a dict with the added prefix.

Something like:

document = {
    'title': unicode,
    'description': unicode,
    'manager': unicode,
}

locations = [{
    'id': uuid.UUID,
    'title': unicode,
    'location': {'coordinates':[float], 'text':unicode}
}]

document.update({'locations-%s-%s' % (num, key): val for num, l in enumerate(locations) for key, val in l.items()})
Uncounted answered 5/1, 2015 at 11:54 Comment(0)
A
1

I think the answer is in this part of the documentation about the .process() method:

Since BaseForm does not take its data at instantiation, you must call this to provide form data to the enclosed fields.

You should use:

f = form()
f.process(data=MultiDict(document))

instead of:

f = form(MultiDict(document))
Analisaanalise answered 22/6, 2020 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.