表单处理
如何通过脚本来展示和处理表单。
1 基本表单处理流程
1.1 图形化定义表单
在软件包里面,采用可视化的方式来定义表单。具体参照表单流程的定义。
表单通过一个包含软件包名字的全面来引用,比如 zopen.tasks:task 表示在软件包 zopen.task 中定义的一个叫做 task 的软件包:
form_obj = root.packages.get_form_obj('zopen.tasks:task')
1.2 表单展示
下面的例子中,表单的定于位于zopen.task应用软件包中task表单,最终表单遮罩显示,会有一个保存按钮,点击后ajax提交后到zopen.test软件包的test1脚本处理:
form = ui.form('zopen.task:task')\ .button('save', '保存')\ .on('submit', context, request, 'zopen.test:test1') view.modal(form)
其中:
- ui.form() 里面直接转递表单的全名
- 通过 on('submit', ...) 指定表单提交处理脚本
1.3 获取表单提交数据 get_submitted
用户提交表单,这时候可以对提交表单数据处理。数据存放在 request.form 中:
title = request.form['title'] # title字段 description = request.form['description'] # description字段
request.form 中的值,会根据字段类型,自动对请求内容做初步的类型转换,比如转换整数、布尔、列表等类型。
这些数据还需要进行表单输入合法性校验,有些数据还需要做清理转换。
对于表单定义:
form = ui.form('zopen.task:task')\ .button('save', '保存')\ .on('submit', context, request, 'xxx.xx:xxx')
得到表单提交的内容:
button, errors, result = form.get_submitted(request.form)
返回值:
- button:点击的按钮
- errors:各个字段的错误信息
- result:表单的数据
对结果进行处理:
# 没有点击button的情况,表示首次访问,弹出展示这个表单 if not button: return view.modal(form) # 提交表单,发生校验错误 if errors: return view.message(errors.values()[0], 'error') # 如果点击了save按钮 if button == 'save': title = result['title'] ....
get_submitted 更完整的调用:
form.get_submitted(request_form, fields=None, check_required=True, keep_multiple=False, pid=None, **options)
其中:
- fields: 仅仅处理那几个字段 - check_required: 是否需要判断必填条件 - keep_multiple: 对于人员、表单、文件夹等选择组件,当设置为单选的时候,是否和多选一样返回list。默认为True - pid:如果有需要分用户存储字段,这个是当前用户id - options: 动态计算需要的额外参数
2 深入表单渲染
2.1 使用表单对象
除了表单全名,可以传递一个表单对象:
form = ui.form(root.packages.get_form_obj('xxx.xxx:xxx'))
或者扩展属性对象:
form = ui.form(root.packages.get_mdset_obj('xxx.xxx:xxx'))
2.3 多个表单按钮
支持多个按钮,并可指定按钮风格。
比如添加一个使用危险风格的按钮:
.button('remove', '删除', klass='danger')
也可以自定义css:
.button('remove', '删除', style="background: yellow")
2.4 多个表单字段组合
通常搜索的时候,需要将表单基础属性和多个扩展属性,组合在一起搜索或者批量编辑。
可以组合组合多个表单定义的字段:
form = ui.form([form_obj_1['name_a'], form_obj_1['name_b'], mdset_obj_2['name_c'], mdset_obj_3['name_d']])
使用 form.get_submitted 得到的result形式是:
{'name_a':value_a, 'name_b':value_b, 'xxx.xx:xx:name_c':value, 'xxx.xx:xx:name_d':value, }
多个表单字段组合,也支持 search 模式。
3 深入表单字段
3.1 更完整的例子 fields
form = ui.form(FORM_NAME, action='')\ # 表单的标题和action .fields(data={'title':'the title'}, errors=errors)\ .hidden({'name1':'value1', 'name2':'value2'})\ # 隐藏变量 .button('save', '保存')\ # 增加一个按钮 .on('submit', '@zopen.sales:test') # 表单,而不是普通的表单
气质 fields() 完整API:
form.fields(data={}, template=None, # 模板 edit_fields=None, # 可编辑的字段 omit_fields=(), # 忽略的字段 errors={}, # 字段错误信息 **options):
- data: 存放各字段初始值, 得到表单定义的初始值,是一个dict: {field_name:value}
- edit_fields 需要编辑的字段,如果不是编辑字段,则自动渲染为只读形式,是一个list: [field_name]
- omit_fields 表单中需要忽略的字段, 是一个 list: [field_name]
- errors 各字段的错误信息,是一个dict: {field_name:error_info}
- template: 个性化的模板, 具体见下面说明
- options: 动态计算需要的额外参数
3.3 自定义布局模板 layout
表单支持三种布局:
table: 左右布局,默认使用:
form.layout('table')
div:也可以改为上下布局:
form.layout('div')
inline: 单行精简布局:
form.layout('inline')
如果以上几种常用布局都不适合你,可以完全自定义模板:
form.template('用户名: $username密码: $password')
模板采用html,其中 $name 表示name字段
3.4 传递字段表达式参数 options
有些表单字段的某些参数是需要动态计算的,比如人员选择,文件选择、表单选择,需要传入context/request才能工作,因此表单必须加上:
ui.form(FORM_NAME).fields(context=context, request=request)
再如,选择字段的可选值,可以传入:
ui.form(FORM_NAME).fields(select_options=[‘a’, ‘b’])
这样,可以在表单的选择字段可选值表达式里面直接使用select_options这个变量
4 深入表单对象
得到form对象:
form_obj = root.packages.get_form_obj(FORM_NAME)
4.2 表单的校验 validate
也可以通过 validate 方法主动检查一下用户输入参数是否合法:
errors = form_obj.validate(result, storage=None, context=context, request=request, view=view, container=container)
其中:
- fields 是需要校验的字段
- result 是准备保存的数据
- storage 之前保存的数据,可以用判断是否有修改
4.3 表单的保存触发脚本
可以直接调用 on_update 脚本,返回值错误信息:
errors = form_obj.on_update(context=context, request=request, view=view, container=context.parent, old_storage = {}) if errors: import transaction transaction.abort() view.message(errors.values(0), 'error')
返回值 errors: 错误值: {field_name:error_info}
如果update传递context参数,调用之后,会自动更改context的修改时间。
4.4 渲染表单字段
得到字段:
field_obj = form_obj[field_name]
渲染表单编辑字段:
field_obj.render_edit(value, context=context, request=request, container=container, **kw)
渲染网页查看方式:
field_obj.render_value(value, context=context, request=request, container=container, **kw)
文本方式方式输出:
field_obj.render_text(value, context=context, request=request, container=container, **kw)
5 组合搜索表单 search_form
上面的表单通常用于新建和编辑,如果需要搜索,表单各个字段通常用于构造条件,比如:
- 文本框:单行文本,全文匹配
- 日期:范围,支持(本周、本月切换)
- 整数:范围
- 小数:范围
- 选择框:包含其一、全部包含
所以表单在搜索的时候,实际每个字段变成包含多个搜索条件输入项的组合字段。
5.1 渲染组合搜索表单
如下渲染搜索表单:
form = ui.search_form(FORM_NAME)
其中:
和 ui.form 参数类似,第一个参数更灵活:
form = ui.search_form(form_obj) # 传递表单对象 form = ui.search_form(mdset_obj) # 传递扩展属性 form = ui.search_form([form_obj1, form_obj2, mdset_obj1, mdset_obj2]) # 多个表单和扩展属性对象的列表
输出的是一个包含各个字段组合搜索条件的新表单
新表单各字段的子字段,实际是另外一个表单,也可定制
5.2 序列化搜索条件 get_submitted
表单每个字段,使用搜索模式进行渲染,可得到用户输入的数据:
error, button, result = form.get_submitted(request.form)
5.3 转为搜索引擎条件 gen_query_json
最终将result转换为搜索条件进行搜索:
query_json = form.gen_query_json(result=result) qs_result = QuerySet().query(query_json)