自动化测试报告系统的一种调研方法和经验总结(mysql+web.py+highchart)

         首先需要描述一些上下文,这是一个自动化测试调度系统中的报告展示页面部分,说白了就是中控调度和驱动测试机执行自动化测试,并且将测试数据和结果日志存入到数据库。而题目中所说的报告系统,就是将这些数据展示给使用人员(测试人员)。最终需要包含的数据,有测试任务查询,测试结果查询,测试明细查询,测试机状态查询,失败截图查询,测试覆盖查询,测试执行情况查询等等。

        一个很小的所谓“系统”,实际上也算是五脏俱全,之前自己也没有做过网站相关的内容,把开发之中遇到的一些问题和分析记录下来,作为积累;事实上,想学好一些东西,最有效的办法就是hands onOk,不谈过多的道理,直接进入主题,下面就是调研和开发过程中的一些点滴。

 

开发语言

        开发的语言选择python,这里面主要有两个原因,一个是项目组其他代码使用Python来写,整体统一比较容易维护,另外一个原因是Python开发速度快(项目组里的人基本上只会python)。其实python确实是一门比较便捷的语言,是我目前学过的开发语言里面比较可爱的一个——最不可爱的是cobol,很多年之后还是不愿意再去碰这种八股文一样的代码。但是真正的环境可能更加复杂,从而选择方面可能考虑得会更加严格。比如可能后台对线程之类要求较高的项目,个人不推荐Python;另外如果服务器是多核的,又想充分利用,那么可能python也不是一个好选择,也许JPython是个候选,但是我个人这时候更推荐google的go,这时候几乎可以认为这玩意就是并发设计的。当然,也不要认为哪个语言就无敌了,到底能开多少线程,并行的处理能力等,服务器的硬件配置才是瓶颈。

 

网站后台

        选择哪个python网站框架的时候,选择性比较多,事实上到现在为止我也没有办法说出哪个框架是最好的。这个世界里没有尽善尽美的方法,在你选择一件事物的美好一面同时,就必须接受它不美好的一部分。如果想尽可能的减少以后不必要的浪费和抱怨,那么最好的办法就是把你计划和选择的权利多放在调研和需求上——这种事情我是这样的理解的,很多时候,当选择了一种架构,就尽可能将它的优势发挥出来,对于它的劣势,一些致命的只能尽可能补救,一些不重要的,可以忽略——如果真的没有劣势,也就没有各种语言或者架构纷争的局面,都有自己的特点和适用性。

    不过这一点python可能差一些,它并不像ruby一样有一个几乎无敌通用的架构,python尽管类库很多,架构也很多,但是大都比较散碎,并没有哪个特别的强大,也许这和它简洁的目标有关。Ok,候选的python架构里有django和web.py,虽然django很大,相对较强,虽然它的很多东西已经配置好了,但是最后还是选择了web.py,主要的原因就是简单自由——一个小的后台系统,没有必要用几十M的django,而且其中大多功能几乎用不到,而且作为给大家练手的小项目,还是直接面对技术本身的更好一些;这里面还有一个更重要的原因,就是这个小小的报告系统中,涉及到对测试机的联通和调度,在通信的时候,我个人更愿意选择web.py,这样我呢个你把注意力更多的放在机器之间的信息交互和命令解析上。这个角度上看,数据的展示,只是这个系统的一部分功能。

    当然,Django中一些方便的东西,比如模板之类的,这些是web.py中没办法去相比的。如果想在使用web.py的时候加入一些其他架构中便捷的东西,可以自己去进行加入。怎么去加入,后面有一个例子,这里暂时不提。至于Python在网站后台开发的一些其他的问题,可以尽可能查阅一些别人已经遇到的情况作为经验,如python全局变量如何管理防止内存不断增加或者泄漏等。

 

模板

    模板的使用个人更倾向于django的方式,而不是web.py的方式,毕竟模板的支持web.py不是很好,假设在web.py中编写模板,可能会遇到jquery编写javascript的标示符冲突,$这个字符必须选择在jquery使用时放弃,换成JQuery.的方式使用它。比如在模板.html中:

$def with (data)



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">



<html xmlns="http://www.w3.org/1999/xhtml" >



<head>



<title>HightChart展示 </title>



<script src="../../static/js/jquery.min.js"></script>



<script src="../../static/js/highcharts.js"></script>



<script src="../../static/js/exporting.js"></script>



</head>



<body>



<script type="text/javascript">



jQuery(function () {



        jQuery('#container').highcharts($data);



    });



</script>



</body>



</html>

 

    好一点的办法,是放弃web.py的模板,选择jinja2来替换,模板上它和django可以看成是一样的使用方法。

    要理解模板,对于相关技术的理解帮助会很大。无论哪种语言写网站,本质上都是写出静态html,然后写出到io,然后通过服务器将Html流返回给用户。html静态网站如此,asp脚本写网站也如此,asp.net jsp,都是如此,不同的只是写出IO流的方式不一样,有的用脚本,有的用类。python当然也不例外,如果你很熟练的使用搜索引擎,可能很轻松的搜索到相关的很多介绍:

        “使用python开发web,最简单,原始和直接的办法是使用cgi标准,在1998年这种方式很流行。现在从应用角度解释它是如何工作: 首先做一个python脚本,输出HTML代码,然后保存成.cgi扩展名的文件,通过浏览器访问此文件。

类似的代码如下:

#!/usr/bin/env python



import MySQLdb



print "Content-Type: text/html\n"

print "<html><head><title>CGI Test</title></head>"

print "<body>"

print "<h1>test case</h1>"

print "<ul>"



connection = MySQLdb.connect(user='tester', passwd='test', db='test_db')

cursor = connection.cursor()

cursor.execute("SELECT c_name FROM tb_test ORDER BY c_id LIMIT 10")



for row in cursor.fetchall():

    print "<li>%s</li>" % row[0]



print "</ul>"

print "</body></html>"



connection.close()

 

      所以其实不管哪种python的网站架构,最终的解决方案,都是如何将各种数据更便捷的写入或者穿插在html中。平心而论,djangojinja2中类似的模板是一种好的模板体系,能够将后台和前端的逻辑轻松的分开,也可以使初学者更快的上手——有些开发人员可能几个小时就能使用django开发逻辑复杂的网站。但是如果练习的话,我不建议初学者直接使用,最好不要在搞清楚这种实现的时候乱使用。这完全是个人的看法,毕竟这种实现是基于全局变量的,一些有编程洁癖的人,并不喜欢过多的使用全局的东西。建议使用python去写大型网站的团队,最好自己可以自己写一套htmlIO流的控制架构,asp.netjsp中的一些机制可能会有帮助。

 

数据库选择

      数据库选择方面,本来应该是没有问题的,大部分人在做数据库的选择和使用的时候,几乎都是老套路;但是其实数据库的内容中,个人觉得,是内容很丰富的一部分,只是用到的内容比较少而已。

      数据库的选择上,一般从事传统系统开发的人,可能选择关联型数据库,而如果国内的一些互联网公司,很可能NoSQL的倾向更多一些。抛开所谓的“大道理”不谈,在具体项目中到底选择哪种数据库,一些很直接因素往往是决定的关键。

      比如,如果考虑省钱的话,一些商用的数据库肯定不在选择范围,更不要提专属的BD2了,除非银行和国企那些烧钱的地方;

      如果考虑到使用方便或者功能很一般,可能有人觉得sqlserver好一些,但是显然比较大,另外就是根本的问题,它的平台限制,但是,请千万不要质疑这些大型数据库的能力——一般都是技术问题,很少是数据库系统的瓶颈引起的;我承认oracle在性能上优于sql server,但是有些微软的项目中,三四千张表的逻辑是很常见的(很多高手听到12306的各种解释后的表情我还记得)。事实上我已经几年都没有使用过sql server了,因为考虑到功能的一般和使用便捷等因素,我通常都是选择mysql的——当然如果不考虑系统性,sqlite是我最常用的。

      另外的一大类NoSql,可能是一些互联网项目的首选,但是并不受一些传统项目的欢迎。对于这样的一些公司,确实要慎重选择是否使用这样的数据库,个人认为并不是逻辑业务不同或者其他什么“理由”引起的,对于选择这种数据库,我个人更在意程序员个人的“能力”。互联网公司的技术人员配备和层次,和传统项目还是有一些不同的。这种NoSql型的数据库,并不是把事务整体安排到一层统一的逻辑,事务是分散到程序中去的,这往往让很多传统程序员没办法适应,他们的逻辑更多的是放在业务层,关系型数据库的事务是很具体的一层逻辑,那更多的是DBA需要考虑的范围。NoSql的环境中,DBA不再是那么很牛的职业了。

      这个小小的系统中,没有什么犹豫的使用mysql来作为数据库系统。

 

数据库使用

      订好了使用mysql这种开源的数据库,一些其他的数据库逻辑和使用基本上也就确定了出来,也就是说,需要面对一些DBA的传统工作。让我具体解释DBA到底需要负责什么具体的事情,我也说不出来,但是数据库的设计,事务的管理,索引的设计,性能优化,数据迁移和持久化,数据备份还原方法等等,都属于DBA负责的范围。

      自己并不是专业的DBA,说到数据库的设计,个人的一点体会是,这种关联型数据库的表设计,主要是三个目的,一个是如何更好的将业务逻辑低耦合的进行分配和隔离,一些方法就是将实体逻辑中存在的对象映射到每个表中,其他需要保存的数据最终也将以高内聚低耦合的方式进行组合,3层架构的设计中很多设计就是如此;第二个目的是如何合理利用磁盘存储数据,减少冗余和重复,这个目的也是关系型数据库的目的之一,我的理解是这个就是如何的去拆表,将业务中的逻辑拆分成无重复的数据进行存储;第三个目的是如何的合表,将第二个目的里的没有冗余数据的各个独立的表的数据,最终合成合理的业务数据。

      对于我们常说的几种范式和索引呀之类的设计,主要也就是为了如何“拆表”和“合表”,我自己使用这种说法,当然我带的一些新员工也都是这么理解的。“拆表”是拆业务逻辑到真实的磁盘数据,“合表”是如何引用每个表合理的完成有机数据的获取。事实上很多时候我们并没有必要关心数据库引擎的底层实现,尤其是关系型数据库,但是需要了解它设计和上层的一些实现。常用的数据库,不管是关系型还是非关系型,存储模型大体相似,基于各种平衡树和跳跃表实现逻辑的方法和缓存层次是不同的,当然这是个人对底层实现的一些理解,也许存在一些问题,但是这个深层的东西不是重点,重点是设计的上层问题,这些可能包括范式,索引,查询等等。

      尽管项目中最常用的还是关联型数据库,但是实际上范式的应用,大多数前三个就够了。这三个范式都是为了设计数据库服务的,如果给定了数据库结构,让我们说出满足哪个范式,个人觉得这东西没任何意义!它的目的是指导如何设计数据库。范式的一些晦涩的说明比较难解释,当然我也不知道大学里面怎么给学生讲——自己大学学的是数学,数据库从没学过,但是工作上我面试过的人简历写的一般很好,但是一些数据库的基本东西却没几个能说明白的。我对这三个范式的理解,第一个范式的目的在于说明没有“表中表”,也就是每一列字段存放的数据,只能是是业务逻辑中的最小信息单元,业务逻辑的最小数据单元也只能放在一个字段里,这依赖于业务逻辑的最小信息单元,也许一个简单的人员表中会把姓名放在一个字段中,但是民政局的系统里,我相信姓和名是分开放的;第二个范式的意思是一个表中需要有候选的主键,这是为了关联和减少冗余的目的;第三范式的内容是独立主键,当然和第二个范式目的一样,但是方式不同。三个范式的内容自己大概也记不太清楚了,所以不确定它们对应的内容的是否正确。

      索引应该是第二个容易被忽略的重点,因为很多人没办法看到它。之前的一个项目里,数据库的表有4000多张,当然还是出了一些性能上的问题,最后请了一个阿三的专家帮忙搞定,对于开发人员,最终是给了一次关于索引的培训和一本写满了索引使用的手册。索引的目的是提高查询速度,特别深的东西一般的项目中使用的少一些,需要了解的是简单的分法,是分为物理索引和逻辑索引,物理索引一般就是主键,它是写在磁盘上的,查询的时候直接按照主键查询,由于主键是按顺序排列的,所以直接进行折半查找;对于逻辑索引,是另外建立一张映射表,将建立索引的列的值进行排序,查找的时候折半查找,然后通过指针找到对应的物理数据——这意味着,查找索引列的内容,和非索引列的内容,出了速度不同,返回的值也会不同

      但是事实上,更多的问题可能暴露在查询语句的使用上——我很怀疑现在大学的教学水平!我以前的一个领导曾经跟我谈过,他们那个时候学习数据库,根本就没有老师讲查询语句,这些是默认学生应该会的,老师们更关注数据库本身的逻辑和设计的实现,那时候的学生通常都能正确的写出查询语句来。但是现在大学的数据库课程,尽管都是在讲数据库查询语句,但是很多学生连功能性查询都没办法实现,更不要提性能了。查询语句中,所有的数据来源于表,所以最先有的,最先去构造的,就是表引用,也就是from之后的东西,所以说,不管group by 或者是order by,还有各种连接,都是构造这个虚拟的表。有了这个表之后,才有后续的where, top/limitselectOk,这里并不是为了专门讨论查询语句,查询语句需要注意的地方就先写这么多。

      关于数据库的另外一个提示,就是永远不要使用select *,这不一个好习惯,并且有时候会带来不好的结果。比如当一张表存放大容量数据的时候,图片或者视频,select *是非常危险的,一不小心就会将内存爆满。

 

webpy中的DB内容

      webpy中提供的DB连接可以说比较简单,大一点的项目还是乖乖的使用其他库进行读写,或者专门自己写一些异步的方法封装一下,这块东西说大就大,说小就小。一个比较简单的办法,可以使用全局的一个池或者队列对异步的数据进行轮询提交,但这只能保证在一台机器上提交的线程没有问题。好在mysql这类的数据库本身对锁还是有支持的。

      webpy查询回来的数据,是以字典的形式存在的——有些人不喜欢这种方式,更喜欢映射成程序中的对象,这样我能在数据处理层避免异常数据,并且加入一些数据处理逻辑——html的各种模板里,我更偏向于传入对象,尤其在web.py的自带模板中,这样的方法可以像写python语句一样在模板里插入脚本。

 

图片处理

      系统中的图片处理,基本上是一些图标的展示,错误截图的点击查看,还有图片下载。这几种情况都是同样都是以流形式实现的。

      展示上基本上是加上http头,然后直接返回,这是最基本的形式,简单的代码如下:

class Images(app.page):



    path='/images/(.+)'



    def GET(self,name):



        ext=name.split('.')[-1]



        image_type={



                    "png":"images/png",



                    "jpg":"images/jpg",



                    "gif":"images/gif",



                    "ico":"images/ico",



                    }



        if name in os.listdir('images'):



            web.header("Content-Type",image_type[ext.lower()])



            return open('images/%s'%name,"rb").read()



        else:



            return web.notfound()

 

      这个是本地的图片,数据库中的图片方法一样,只是改成获取字段的字节流之后返回。

      错误截图需要点击链接后在浏览器页面中打开,这种情况通常我们需要创建一个新的模板,模板里对图片进行约束,然后这个模板负责对图片的展示,模板和类的简单代码如下:

$def with (data)



<html>



<body style="margin: 0px;">



<img style="-webkit-user-select: none; cursor: -webkit-zoom-in; " src="../snapshot/$data">



</body>



</html>

 

 

class snapshot():



    def GET(self,id):



        return render.snapshot(id)

    

 

 

日志

      日志上由于没有过多的需求,所以简单的对pythonlog进行一些封装就可以使用了,由于环境使用UTF8编码,这部分也进行了处理,如下:

class EncodeStreamHandler(logging.StreamHandler):



    def __init__(self):



        logging.StreamHandler.__init__(self, sys.stdout)



        pass



    def emit(self, r):



        try:



            msg = self.format(r)



            stream = self.stream



            if type(msg) != type(u''):



                import chardet



                if chardet.detect(msg)['encoding'].startwiths('GB2312'):



                    msg = msg.decode('gbk')



                elif chardet.detect(msg)['encoding'].startwiths('UTF-8'):



                    msg = msg.decode('utf-8')
else:
pass stream.write(msg.encode(stream.encoding)) self.flush()
except (KeyboardInterrupt, SystemExit): raise "Encode stream error" except: self.handleError(re)

 

图表

      图表的部分,我们在开发过程中调研了很久,始终没有办法找到一个合适的解决方案。在页面中对图表进行展示,架构有很多。基本上是静态方式,js方式和flash方式。

      flash的方式直接被抛弃了,一个简单的自动化测试报告系统,没有必要提供flash级别的图表,不然使用页面查看数据会很慢。

      最早并没有考虑到数据的动态性,所以使用最简单的办法,使用pyplot绘图,然后返回流到前台。我承认我恋旧——大学做了4年数学计划和模型,自己很喜欢matlab这样的方式,做一些科学计算,pytplot是首选(更多资料见官网http://matplotlib.org/gallery.html),但是它并不适合做前台页面图形的处理,它是静态的,并且一旦生成了,分别率也很难调整,也不支持中文写入,但是还是把当初实现的方式记录了下来,因为觉得它很有趣,并且我也真的为他醉心了很久:

def genStatPic(_n,_id,_num_P,_num_T,_name,_machinelist,_width=0.35):

    try:

        import numpy as np

        import matplotlib.pyplot as plt

        from mpl_toolkits.axes_grid1 import host_subplot

        import mpl_toolkits.axisartist as AA

        #locker.acquire()

        ind=np.arange(_n)*0.6

        if len(ind)>20:

            return

        width=_width

        ax = host_subplot(111, axes_class=AA.Axes)

        ax.set_xlim(0,100)

        count=len(_machinelist)

        _pass_L=[_num_P[i]*100/_num_T[i] for i in range(count)]

        _fail_L=[(_num_T[i]-_num_P[i])*100/_num_T[i] for i in range(count)]

        p1=ax.barh(ind,_pass_L,width,color='g')

        p2=ax.barh(ind,_fail_L,width,color='r',left=_pass_L)

        plt.yticks(ind+width/2., _machinelist)

        ax.axis["bottom"].major_ticklabels.set_visible(False)

        ax2=ax.twin()

        ax2.set_xticks([0,10,20,30,40,50,60,70,80,90,100])

        ax2.set_xticklabels(['$'+str(i*10)+'\%$' for i in range(11)])

        ax2.axis["right"].major_ticklabels.set_visible(False)

        ax2.set_xlabel('Case result of task '+_name)

        plt.legend( (p1[0], p2[0],), ('Pass', 'Fail'), shadow = True, loc = (0.01, 0.85))

        ax.annotate('total : %d'%max(_num_T), xy=(.9, .985),

                xycoords='figure fraction',

                horizontalalignment='right', verticalalignment='top',fontsize=15)

        for rect in range(len(p1)):

            width = int(p1[rect].get_width())

            lastDigit = width % 10

            rankStr = str(_num_P[rect])

            if (width < 5): # The bars aren't wide enough to print the ranking inside

                xloc = width + 3 # Shift the text to the right side of the right edge

                clr = 'black' # Black against white background

                align = 'left'

            else:

                #xloc = 0.98*width # Shift the text to the left side of the right edge

                xloc=width/2

                clr = 'white' # White on magenta

                align = 'right'

            yloc = p1[rect].get_y()+p1[rect].get_height()/2.0 #Center the text vertically in the bar

            ax.text(xloc, yloc, rankStr, horizontalalignment=align,

                    verticalalignment='center', color=clr, weight='bold')

            rankStr = str(_num_T[rect]-_num_P[rect])

            if (width >95): 

                xloc = width -3  

                clr = 'black' #

                align = 'left'

            else:

                xloc=(100-width)/2+width

                clr = 'white' 

                align = 'right'

            yloc = p1[rect].get_y()+p1[rect].get_height()/2.0 

            ax.text(xloc, yloc, rankStr, horizontalalignment=align,

                verticalalignment='center', color=clr, weight='bold')

        plt.gcf().set_size_inches(18,5)

        if not os.path.exists('pic'):

            os.makedirs('pic')

        if not os.path.exists('pic'):

            print 'create pic failed'

        plt.savefig(r'pic\%s_stat.png'%str(_id),transparent=False)

        plt.clf()

    except Exception,e:



print e

 

      一个函数体里写这么多东西不会受推荐,而且这里面绘制的是一个综合图,包括柱形图和一个table,并且颜色也做过动态处理。由于当初没有选定使用pylot,所以并没有对这个复杂图形的生成再次封装一下,一个问题是最有一定要对图片进行plt.clf()的处理,这些都是全局的,多个session对图表进行访问的时候,不进行plt.clf的清理,数据之间会相互影响,后果就是图片始终都是一样的。

 

HighChart

     最终图表的架构上,我选择了highcharts, 自己不是很喜欢前端的东西,但是它确实很适合我们,也很实用,它存在的一些问题,也都可以解决或者化解。它支持中文的标签,支持动态图表,漂亮的样式等等。虽然源码js下载慢了一些,虽然执行js需要吃很大资源。。。把远程js下载到服务器就可以了,而且对于现在流行的电脑配置,浏览器执行js吃掉的资源,相对并不是很大——和打开那么render进程相比。highcharts的资料可以查询官网:http://www.highcharts.com/demo/

     但是highcharts是一套前台架构,也就是以为着需要在模板中使用它。平心而论,在前台上直接写,还是很漂亮的,但是。。。这个并不可取,移植、复用。。。总的来说就是太专属了,而且写死了。

     如果直接在模板里写,需要把结构写死,然后将很多参数传入,类似下面这种方式:

<td valign="top">



            <div id="container" style="min-width: 400px; height: 400px; margin: 0 auto"></div>



            <script type="text/javascript">



            jQuery(function () {



                jQuery('#container').highcharts(



                {



                subtitle:



                    {text: 'percentage of data', x: -20},



                yAxis:



                    {



                        max: 7, title: {text: '%'},



                        plotLines:



                        [



                        {color: '#808080', width: 0.10000000000000001, value: 0}



                        ],



                        min: 0



                    },



                series:



                    [a



                        {lineWidth: 0.5, data: $[x.category1 for x in stats], name: 'category1'},



                        {lineWidth: 0.5, data: $[x.category2 for x in stats], name: 'category2'},



                        {lineWidth: 0.5, data: $[x.category3 for x in stats], name: 'category3'},



                        {lineWidth: 0.5, data: $[x.category4 for x in stats], name: 'category4'},



                        {lineWidth: 0.5, data: $[x.category5 for x in stats], name: 'category5'},



                        {lineWidth: 0.5, data: $[x.category6 for x in stats], name: 'category6'},



                        {lineWidth: 0.5, data: $[x.category7 for x in stats], name: 'category7'},



                        {lineWidth: 3,color: '#FF0000', data: $[x.total for x in stats], name: '汇总'},



                    ],



                title:



                    {  



                        text: 'Statictisc of Test', x: -20



                    },



                tooltip:



                    {



                        valueSuffix: '.'



                    },



                plotOptions:



                    {



                        series:



                            {marker: {radius: 0.5}}



                    },



                xAxis:



                    {



                        tickInterval: $(len(stats)/4),



                        categories:



                               [



                                   $for stat in stats:



                                        '$stat.category1',



                                ]



                    },



                legend:



                    {



                        verticalAlign: 'middle', align: 'left', layout: 'vertical', borderWidth: 0



                    }



                }



                );



            });



            </script>



</td>

 

     当然我们可以直接在python生成类似的代码,然后直接在模板中使用参数替换,这样至少将生成的逻辑提到了代码层面,类似于这样的模板:

            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">



            <html xmlns="http://www.w3.org/1999/xhtml" >



            <head>



                <title>Chart </title>



            <script src="../../static/js/jquery.min.js"></script>



            <script src="../../static/js/highcharts.js"></script>



            <script src="../../static/js/exporting.js"></script>



            </head>



            <body>



            <div id="container" style="min-width: 400px; height: 400px; margin: 0 auto"></div>



            <script type="text/javascript">



            jQuery(function () {



                jQuery('#container').highcharts($data);



            });



            </script>



            </body>



            </html>

 

      这种方法可以很灵活的生成highcharts的方法体,但是似乎有点太灵活了。。。他一点可以复用的东西都没有。Web.py的一个很大的不便之处,在于没办法在模板上动态的生成html标签,这直接导致没有办法结构化的组织页面标签结构。要么就整个html都在python中生成,要么只能动态的编辑里面的值,而不是标签本身。这是出于安全性的做法,但是牺牲了灵活性。在写highcharts时,这样的需求可能更多一些,一种好的办法,是可以封装一个写highcharts的类,里面把highcharts中可能存在的元素,都做好一个生成方法,最终整个架构都可以使用这个类进行highcharts的生成。一个类似的结构如下:

class PCGen():



    __temp_file__ = None



    __log__ = None



   



    def __init__(self, temp = "", log = logging.getLogger('')):



        self.__temp_file__ = temp



        self.__log__ = log



    def _gen_subtitle_(self,s):



        return ""



        pass



   



    def _gen_Axis_(self, s):



        return ""



 



    def _newline_(self, s):



        return "<br>%s</br>" % s



   



    def _gen_series_(self, s):



        return ""



   



    def _gen_tooltip_(self, s):



        return ""



   



    def _plotOptions_(self,s):



        return ""



 



    def _legend_(self, s):



        return ""



   



    def reset_hc_(self):



        pass

 

      至于如何去丰满这个结构,可能需要根据自己的具体需求了。

分页

      分页并不是什么老生常谈的问题,基本上哪个大型的网站开发架构都会提供,但是貌似web.py没有。这也不是什么严重的问题,它并不是一个多么大型的架构,而是属于可爱那一类的。可以使用最原始的办法进行分页的处理,类似方法如下:

class ProbbsPage:



    def __init__(self, total, per = 10):



        self.total=total



        self.per=per



        self.url=''



        self.page=1



   



    def set_url(self,url):



        self.url=url



        return self         



   



    def set_page(self,page):



        self.page=int(page)



        return self



   



    def show(self):



        if self.total%self.per==0:



            pages=self.total/self.per



        else:



            pages=self.total/self.per+1



        if self.page<6:



            limit_s=1



        else:



            limit_s=self.page



       



        if pages<(limit_s+10):



            limit_e=pages



        else:



            limit_e=limit_s+10



           



        #pagination='<span>%s/%s pages </span>'%(self.page,pages)



        pagination='''<span">共有<strong>共%s</strong> 条记录,当前第<strong> %s</strong> 页,共 <strong>%s</strong> 页</span>'''%(self.total,self.page,pages)



        for i in range(limit_s,limit_e+1):



            if i==self.page:



                pagination+='<a class="cur" href="javascript:void(0);">%s</a>'%(i,)



            else:



                pagination += '<a href="%s">%s</a>'%(self.url%i,i)



        return pagination



 



if __name__=="__main__":



    pagination =ProbbsPage(101,10)



    url = '..test/%s';



    page_html = pagination.set_url(url).set_page(2).show() 

总结

      基本上,按照上面说的这些知识,一些小系统可以比较快速的建立起来,也可以满足一般的需求,但是web.pyhighcharts可能国内使用做网站的还不是很多,一些资料也不全面,上面提到的一些东西还有待修改,也算是一种实践吧。

你可能感兴趣的:(highchart)