::-- ZoomQuiet [2005-12-11 04:51:21]

1. K5日:随时重构

快速利用已有的所有技巧,重构功能实现

  • 让原先分散的.pih 们也整合到一个 mana.ks 事务页面中吧!

1.1. 悠然 Leo

   Ctrl+`

从来没有如此让你放心过……

"

  • 只要保证,所有.ks 中有 clone 的<< htmlcode >>

    • 所有.ks 中的响应函式中有 clone 的<< pagehead >><< pagefoot >>

    • 就等于随时控制了所有页面的外观!

1.2. 调整事务响应

将问卷的使用和管理拆分为专门的两个事务页面

  • index.ks 作为默许访问的页面是问卷回答/统计的使用事务页面

  • mana.ks 作为权限用户的问卷设计事务页面

  • 那未,首先,用户从/index.ks/login 登录后记录的信息,怎么样传递到 mana.ks

1.2.1. 页面间传递对象

当然的,你期望是完整的对象传递,而不用又要判别,记载……

  • 不是有 pickle 序列化模块嘛!

  • 尝试将对象序列化为字串作为页面间的参数捅过去就好哪!
    • 打印当前的会话容器序列化字串看一看:

      print pickle.dumps(sess.usr)
      

"

  • 唉呀呀……有空格,以及其它符号的!一定会被误解为不同参数的……
  • 找呀找呀,找朋友,找到一个urlsafe_b64encode(s) base64 模块中的

  • OK 组织测试一下子:

       1 v = base64.urlsafe_b64encode(pickle.dumps(sess.usr))
       2 print v
       3 print "<br/>"
       4 print pickle.loads(base64.urlsafe_b64decode(v))
    

"

  • 非常理想!就用之了!

   1 print SPAN(A('> 编辑管理问卷'
   2         ,href="../mana.ks/edit?qp=%s&obj=%s"%(
   3             qpname
   4             ,base64.urlsafe_b64encode(
   5                 pickle.dumps(sess.usr))
   6                 )
   7             )
   8         ,id="mana")

  • 在 问卷回答界面中追加一个编辑的链接就好
    • 注意:
      1. 使用 ../mana.ks 是因为 .ks 事务页面实际都是进一层的*.ks/action访问,所以要链接到另外的事务页面,要使用相对路径修正的

      2. <A> 追加了一个 id="mana" 的属性是为了让CSS 击中,进行显示的处理,对应的CSS定义是:

        SPAN#mana{border-bottom: 2px solid #778;
            border-left: 2px solid #778;
            float:right;color: #930; 
            background-color: whitesmoke; padding: 2px;}
        
        效果如下:

    "

    • 当然的,应该只有权限用户才会看到此链接
    • 不过,开发阶段完全开放——反正要实现版本管理不用怕的说;-)

    1.3. 重构编辑流程

    当然的所谓 mana.ks 事务页面就是要代替以前使用7个文件完成的问卷编辑流程

    • 二话不说先将成功运行的 index.ks 节点 clone 成 mana.ks 然后快速的修剪

    • 将原先qpage.pyexpage(dict) 重构为 index.ks_qshow(dict,aim)

      • 99% 的代码都不变,仅仅是传入的参数重新命名而已

           1 def _qshow(dict,aim):
           2     """将dict 内容输出为回答问卷
           3     """
           4     exp = ""
           5     p = Karrigell_QuickForm('fm_kq','POST',aim,dict.desc.desc)
           6     p.addElement('node','<ul>','')
           7     # 深入数据
           8     qli = {}
           9     k = [int(i) for i in dict.ask.keys()]
          10     k.sort()
          11     for i in k:
          12         ask = dict.ask[str(i)]
          13         qk = [j for j in ask.keys()]
          14         qk.sort()
          15         for q in qk:
          16             if 1==len(q):
          17                 qli[q] = ask[q]
          18             else:
          19                 pass
          20         question = ask["question"]+"<sup>答案::%s</sup>"%ask["key"]
          21         ## 这里美化一下子,奇偶行使用不同的CSS来控制
          22         if i%2 == 0:
          23             p.addRadioList("cr_ask%s"%i
          24                    ,question
          25                    ,qli
          26                    ,"even")
          27         else:
          28             p.addRadioList("cr_ask%s"%i
          29                    ,question
          30                    ,qli)
          31         p.addJSRule("cr_ask%s"%i,"问题%s "%i)
          32 
          33     p.addJSValidation()
          34     p.saveJSRule("js/validation-config.xml")
          35     p.addElement('node','</ul>','')
          36     p.addGroup(["submit","btn_submit","提交","btn"]
          37                ,["reset","btn_reset","重写","btn"])
          38     exp += p.export()
          39     return exp
        
    • 同理,使用原先十分之一的时间,快速将一连串的 .pih 动态页面,改写为 .ks 事务页面
    • 只是为了增加版本管理的功能,追加了一个操作

      # 先复制一下子
      shutil.copy2(qpage,qpage+".%s"%time.strftime("%y%m%d%H%M%S"
                                                   , time.localtime())
                   )
      
      • 使用 shutil高级文件处理模块,在问卷提交后,先复制一份历史版本

    1.4. 历史版本

    习惯的Wiki的反悔模式,当然的也想自个儿弄一个

    "

    • 几次小的尝试性修改,在 /q 中聚集了一批命名有模式可寻的问卷设计稿

    • 直接利用问卷列表的处理代码,小修改一下子,就成为历史版本列表的实现,归到

         1 def historic(**var):
         2     << pagehead >>
         3     @others
         4     << pagefoot >>
      
    • 可以看到现在连事务页面中的具体请求也可以八股化了
      1. << pagehead >> 标准的页头 信息

        • 不过是一个print _htmhead("标题文字") 将预定HTML 代码少量处理后输出的小函式

      2. @others 包含所有具体行为的章节脚本

      3. << pagefoot >> 标准的页底 信息

        • 更加简单的 print htmfoot 打印行为,将 Powered by:...什么的广告全都统一而已

    1.4.1. 关键代码

       1 qnow = fnmatch.filter(os.listdir(conf.qpage.qpath)
       2                        , '%s.cfg.*'%sess.usr["qp"])
       3 print "<UL>"
       4 qnow.reverse()
       5 for l in qnow:
       6     s = l.split(".")
       7     print LI(A("""%s 
       8              <sup>%s/%s/%s %s:%s:%s 版本</sup>"""%(s[0]
       9              ,s[-1][:2]
      10              ,s[-1][2:4]
      11              ,s[-1][4:6]
      12              ,s[-1][6:8]
      13              ,s[-1][8:10]
      14              ,s[-1][10:]
      15              ),href="edit?his=%s"%s[-1]
      16                 )
      17              )
      18 print "</UL>"
    

  • 老技巧,使用 fnmatch 模块将吻合模式的文件搜索为一个列表对象
    • 现在的 模式:'%s.cfg.*'%sess.usr["qp"]

      • 即,当然要看的问卷名+".cfg"+".其它什么的"
      • ".其它什么的"就是之前你随手复制了一下子先时定的

        time.strftime("%y%m%d%H%M%S", time.localtime())
        
        时间字串
      • 那未知道是 年月日时分秒 的组合,使用字串的切片操作,一下子就重新组织输出好了

    • 再随手加个链接,给个?his= 的历史版本标识

    • 回头修改一下子

         1 def edit(**var):
         2     #...
         3     if "his" in QUERY.keys():
         4         #进入历史版本编辑
         5         qpage = "%s%s.cfg%s"%(conf.qpage.qpath
         6                     ,sess.usr["qp"]
         7                     ,"."+QUERY["his"])
         8     else:
         9         qpage = "%s%s.cfg%s"%(conf.qpage.qpath
        10                     ,sess.usr["qp"]
        11                     ,"")
        12     #...
      
      • 作个小判定,令编辑处理,知道什么时候读要求的历史版本

    1.4.1.1. 进一步的

    突然你想列出各版本的内容多少差异……

    • 搜索一下子手册,发现了 os.stat()

      <sub>大小:%sb</sub>
      ...
      ,os.stat(conf.qpage.qpath+l)
      

    • 返回元组有文件对象的:
      1. st_mode (protection bits),
      2. st_ino (inode number),
      3. st_dev (device),
      4. st_nlink (number of hard links),
      5. st_uid (user ID of owner),
      6. st_gid (group ID of owner),
      7. st_size (size of file, in bytes),

      8. st_atime (time of most recent access),
      9. st_mtime (time of most recent content modification),
      10. st_ctime (platform dependent; time of most recent metadata change on Unix, or the time of creation on Windows).
    • ST_SIZE 是我要的

    • 但是具体是哪个?咳咳咳,看标识,只有两个是L长整,有变化的就倒数第四个,所以:

      <sub>大小:%sb</sub>
      ...
      ,os.stat(conf.qpage.qpath+l)[-4]
      

    1.4.2. 可变参数的意义

    • 现在你可是对Python 函式的可变参数深以为然了
    • 本来按照PHP 的习惯,传递的页面参数自然会变成内存对象,
    • 但是在KarriGell 中如果不严格匹配

    " 这总是会出参数不匹配的错误

    • 有了万能的(**var) 声明,一切都总能兼容!

    1.5. 明日任务

    哇呀呀!没有想到再古怪的想象,KarriGell 都支持!接下来……

    • 就是要根据有效的成员信息来进行成绩的统计汇报了

    1.6. 实例下载

    使用 SVN 下载:

    1.7. 讨论


    返回 KarrigellWebDev -- 快速体验K开发