WTForms:FieldList 的 FormField 无法加载嵌套数据

8 投票
3 回答
1561 浏览
提问于 2025-04-18 16:32

我在一个字段列表里有一个自定义字段,叫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)

当我提交这个表单时,它会保存到一个对象里,像这样:

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

但是当我尝试在一个GET处理程序中加载数据到表单时,除了locations以外的所有内容都能正常加载:

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

我做了一些调试,发现WTForms在把文档的数据加载到表单时,会查找'locations-0-location'这个键,但MultiDict()里并没有这个键。MultiDict并不会把字典列表转换成'locations-i-...'这样的键。

那么,针对这种嵌套的数据结构,正确的WTForm写法应该是什么呢?

3 个回答

1

我觉得答案在文档的这一部分,关于.process()这个方法:

因为BaseForm在创建的时候并不会直接接收数据,所以你必须调用这个方法来给里面的字段提供表单数据。

你应该使用:

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

而不是:

f = form(MultiDict(document))
1

我也遇到过同样的问题,后来我通过把列表转换成一个带有前缀的字典来解决了这个问题。

大概是这样的:

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()})
4

使用WTFORMS 2.1

这里是数据:

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

你可以用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)

试试这个:

f = ProjectForm()
f.process(data=document)
f.locations.data

撰写回答