status |
正式 |
完成度:97% |
Contents
1. KDay 3:使用第3方模块规范化表单
Cheetah 只能输出有配套模板的页面内容,但是……
- 对于经常变化的表单,有什么更好的方式来生成表单?
小白开始了 Pythonic 重构思考,感觉 VC 格局中的 V ~ view,展示层,少不了人手工对 HTML 为格式的页面模板进行维护, 而且每个对应的功能页面就要写个模板, 再且模板文件的复用非常难...
所以,想起在 CDays 故事演练中使用过的 Karrigell 快速表单模块:
1.1. Karrigell_QuickForm
~即有之,则用之!
- 示例:
1 from Karrigell_QuickForm import Karrigell_QuickForm
2
3 p = Karrigell_QuickForm('teste','POST','foo.py','Authentication')
4 p.addElement('text','login')
5 p.addElement('text','password')
6 p.addRule('login','required',"Login is required!")
7 p.addGroup(["submit","botao_enviar","submit","Send"]
8 ,["reset","botao_limpar","reset","Clear"])
9 """根据习惯hack! 原先的自动生成 value 的为指定按钮文字.
10 p.addGroup(["submit","botao_enviar","Send"]
11 ,["reset","botao_limpar","Clear"])
12 """
13 p.display()
1.1.1. 改造
毕竟是 alpha 版本,居然还是全面的table 结构!
- 代码也很ugly 哪!
图 KDay3-2 使用Leo自动整理后的情景 Upload new attachment "kday3-leo-adjust.png"
- 立即着手改造单选列表生成:
1 def addRadioGroup(self,name,value):
2 """add a radio element - addRadioGroup('genre',{'male':'Male','female':'Female'})"""
3 self.form_list.append("<tr><td align='right' valign='top'><b>"+name.title().replace('_',' ')+":</b></td> <td valign='top' align='left'>")
4 radio = ""
5 t = value.items()
6 for a,b in t:
7 radio = radio + "<input type='radio' name='"+name+"' value='"+a+"'>"+"<label><font face=verdana size=2>"+b+"</font></label><br>"
8 self.form_list.append(radio+"</td>")
9 self.form_list.append("</tr>")
1 def addRadioList(self,name,desc,value,id=""):
2 """add a radio element export as UL LI group
3 """
4 htm = """
5 <li id='%s'><b>%s:</b>
6 <ul>"""
7 self.form_list.append(htm%(id,desc))
8 radio = ""
9 t = value.items()
10 tmpl = """<li>
11 <input type='radio'
12 name='%s'
13 value='%s'>
14 <label>%s</label>
15 """
16 for a,b in t:
17 radio = radio + tmpl%(name,a,b)
18 self.form_list.append(radio+"</ul></li>")
1.1.2. 利用
直接将昨天的展示函式修改一下子就应该好用的!
def expage(dict): 对应的修改为:
1 def qpubish(dict):
2 exp = ""
3 p = Karrigell_QuickForm('fm_kq','POST','#',dict.desc.desc)
4
5 p.addElement('node','<ul>','')
6 # 深入数据 基本和昨天的一样,仅仅是输出时使用 Karrigell_QuickForm 对象而已
7 qli = {}
8 k = [int(i) for i in dict.ask.keys()]
9 k.sort()
10 for i in k:
11 ask = dict.ask[str(i)]
12 qk = [j for j in ask.keys()]
13 qk.sort()
14 for q in qk:
15 if 1==len(q):
16 qli[q] = ask[q]
17 else:
18 pass
19 p.addRadioList("cr_ask%s"%i
20 ,ask["question"]
21 ,qli)
22 p.addElement('node','</ul>','')
23 p.addGroup(["submit","btn_submit","提交"]
24 ,["reset","btn_reset","重写"])
注意到原先的 Karrigell_QuickForm 只有display(),要求表单页面立即输出, 但是小白现在需要进一步的HTML 处理后再输出
所以有了以下修订
1 def export(self): 2 """ export the html form code so people can do something for them self 3 """ 4 exp = "" 5 ... 6 for c in self.css_list: 7 exp += c+"\n" 8 for i in self.form_list: 9 exp += i+"\n" 10 return exp
基本上就是将原先的 print 替换为 exp+= 记录为字串对象然后返回
还有def addElement(self,element,name,options=None): 中追加更自由的任何HTML 节点输出:
elif element == 'node': self.form_list.append(name)
1.2. JS 问题
一切顺心,表单顺利自动生成了,但是,Karrigell_QuickForm 提供的前端表单检验居然不支持Radio列表的!
- 呜乎!这是个问题哪...
- 因为:如果不是所有人将所有问题都回答完就提交的话:
- 不检验这种情况,则成绩统计没有意义;
- 交给服务端检验,浪费带宽!还要想办法记录上次是谁回答的问题情况, 然后再返回/提示/要求重答等等等等...
1.2.1. 继续发掘
现在的问题是有什么现成的可以模式化的定义表单检验的前端JS组件?
TiosnG ![ti'aosn'gu]
There is one site named Google! -- 哈哈哈!!运用这个流传在行者们中的咒语,翻查了一下,确认 Validation ~ 有效性检查是小白想要的检验的学名,于是得到...
JVF~JavaScript Validation Framework -- Javascript 有效检验框架 国人作品!
图 KDay3-3 2004年当时的JVF作品页面情景
详细:: JVF是AMOWA社区作品,该社区致力于创建一个实用精巧的Ajax框架; 当年的官网是 http://www.amowa.net 现在迁移到 http://buffalo.sourceforge.net/ JVF 可以从 http://cosoft.org.cn/projects/jsvalidation 获得; 精巧地址:http://bit.ly/2icRKJ 相关的动态网页技术,在PCS401 DHTML 进行分享
1.2.2. 迁就,先!
为了与KarriGell 配合,当前需要:
在配置文件中,追加声明jvf=%(base)s/karriweb/questionnaire/js 这样的专门虚拟目录发布,以便,其它各种应用也可以享受JVF 支持
JVF 实际运行的 validation-framework.js 本身, 也要声明可访问的目录:var ValidationRoot = "/jvf/";
小量修订 JVF 声明错误输出的页面元素 类 名 #errorDiv
ValidateMethodFactory.validateRequired = function(field, params) { ... window.location.replace("#errorDiv");
使用replace 来减少不必要的页面刷新使用 p.saveJSRule("../js/validation-config.xml") 声明提交时要检验的表单元素
注意: 测试JS 成功引用否的小技巧: `alert("Include KO!");` 在JS脚本中加入强制提示,刷新页面,如果见到已经包含的信息就表明引用路径对了!
1.2.2.1. KQF 对JVF 的迁就
JVF的使用很有个性,使用外部的XML 文件进行检验行为的设置...
所以,对应的增补Karrigell_QuickForm
addJSRule() 追加专门的JVF 规则
1 def addJSRule(self,name,message): 2 """add a xml rule for javascript checking 3 """ 4 exp = self.JSvMXLnode%(name,message) 5 self.JSvRules.append(exp)
addJSValidation() 追加调用JVF的页面行为
1 def addJSValidation(self): 2 """add a javascript rule in order to validate a form field 3 - addRule('elem_name','required','Name is required!') 4 """ 5 orig = "enctype='multipart/form-data'" 6 repl = """ 7 onsubmit='return doValidate("%s");' 8 """ 9 begin_form=self.form_list[0].replace(orig 10 ,repl%self.name) 11 self.form_list[0] = begin_form
saveJSRule() 记录规则集合为JVF需要的XML
1 def saveJSRule(self,xml): 2 """exp and save a xml rule for javascript checking 3 """ 4 exp = "" 5 for node in self.JSvRules: 6 exp+= node 7 #exp = self.JSvXMLtmpl%(form,exp) 8 open(xml,'w').write(self.JSvXMLtmpl%(self.name 9 ,exp) 10 )
对应的KQF中追加统一的预设声明
self.JSvXMLtmpl="""<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE validation-config SYSTEM "validation-config.dtd"> <validation-config lang="auto"> <form id="%s" show-error="errorMessage" onfail="" show-type="first"> %s </form> </validation-config> """ self.JSvMXLnode = """ <field name="%s" display-name="%s" onfail=""> <depend name="required" /> </field> """ self.JSvRules = []
1.2.3. 果然不出所料
仅仅追加少量代码就完成所想的客户端JS验证功能
在原先问卷解析函式中,追加准备好的JVF 支持
def qpubish(dict): ... ## 具体问题解析 k.sort() for i in k: ... p.addJSRule("cr_ask%s"%i,"问题%s "%i) # 声明此处要进行JS检验 ## 整体行为处理 p.addJSValidation() p.saveJSRule("js/validation-config.xml") #收集检验声明,生成JVF 使用的外部XML设置文件 ...
- 没有任何悬念的完成任务!
图 KDay3-4 加载JVF 后,表单有任何项没有提交就报错
1.3. 页面编码
从开始使用 Karrigell ,小白在 FireFox 浏览器中就发现有中文乱码问题...
图 KDay3-4 页面乱码现象
- 小白努力的检查了源代码,模板代码,将所有应该声明或是本身也另存为了 utf-8; 甚至于发现配置文件中有疑似输出编码声明的地方也逐一打开,比如说:
[Server] ... outputEncoding = utf-8 ... # determine if form fields should be encoded encodeFormData = 1 ...
- 但是依然是乱码,每次非得手工将浏览器的字符编码设置成 utf-8 才正常...
- 怎么回事儿呢? 小白不得不到列表中吼,经过行者们的研究,确认是 Karrigell 内部处理编码有问题,不过,想解决也非常简单,使用以下的页面响应编码声明:
RESPONSE['Content-Type'] = "text/html; charset=utf-8"
脚注: 行者们讨论中文乱码问题的原始记要在 啄木鸟社区维基: http://wiki.woodpecker.org.cn/moin/MiscItems/2008-08-05
1.4. 合理滥用Leo
到现在页面都是白板!不能忍了!使用CSS!
图 KDay3-5 通过Leo 每个页面复用嵌入的css 定义
注意 <<k_base>> 节点前的小红箭头记号 ~ 这表明此节点是从 别处 克隆过来的!
1.4.1. CSS设计技巧
复用以前自个儿的积累是非常好的事儿!
- 颜色的设计是个问题,不过有好工具来偷!
图 KDay3-6 演示 redalt.com 的CSS颜色分析工具
1.4.2. CSS
每一需要CSS美化的页面都加<<k_base>> 引用,
引用都是从复用代码 中clone 过来的同一节点
包含的就是k_base.css 小白根据 Django 社区的样式修剪成的一个通用CSS设计,套用到当前的系统中
图 KDay3-7 问卷管理和展示CSS效果
1.5. 小结
图 KDay3-8 最终问卷效果
- 当然在小白的开发故事中,这不是最终接受的方案,精彩还要继续……
- 现在所有的基本功能点都有了,接下来的就是要实用化:
- 支持多用户,得有用户验证,要登录
- 支持多问卷选择/回答/编辑
1.6. 实例下载
使用SVN下载地址:
http://openbookproject.googlecode.com/svn/trunk/LovelyPython/KDays/kday3
- 注意有在上层安置的 JS-JVF 目录:
- 本日成果
kday3 |-- Karrigell_QuickForm.py KQF快速表单模块 |-- tryKQF.py KQF试用页面 |-- dict4ini.py Limodou 贡献的 ini 解析模块 |-- q/ 问卷设计文本收藏目录 | |-- easy051201.cfg 第一份问卷设计 | |-- easy051201.cfg.080824231959 问卷设计历史存档 | `-- easy051201.cfg.080824232025 |-- mana.pih 问卷设计页面 |-- qdesign.py 问卷设计实际行为脚本 |-- qpage.pih 问卷复审页面 |-- qpage.py 问卷复审实际行为脚本 |-- qprint.pih 问卷展示页面 |-- qprint.py 问卷展示实际行为脚本 `-- questionnaire.tmpl 问卷展示模板
1.7. 练习
在前面章节练习mysite的基础上, 完成以下功能:
(1) 利用Karrigell_QuickForm改写编辑页面(edit), 增加更多的文章属性, 如日期, 标签, 引用链接等;
- (2) 实现了上述之后, 使用JVF, 依次校验用户输入的有效性;
- (3) 提示: 可以设计一个文章类, 多个文章对象可以利用pickle保存; 最终应该能够实现新建或修改文章并保存入本地文件的功能.
返回 KDays实例故事
::-- ZoomQuiet [2005-12-11 04:50:15]