十月总结

 到月末了,对这两个月做一下总结。

首先是 VirtLAB,这个从三月开始的自动化测试项目,该项目用于在 QE 团队内部替代 RHTS,由于是重新设计的 Database schema,所以我可以充分发挥 Django 自身的优势,也是因为通过 VirtLAB,使我的 Django 水平得到了极大提高,同时由于 UI 前端是自己编写的,所以对 Javascript 也远远胜过之前。现在无论是 Django 本身的 ORM,Template,Form 都很难难到我了,自定义 ORM model field、Form 的 RequestContext Processor,Field 和 Template 的 Tag、Filter 也都得心应手。

在这两个月里,VirtLAB 发展到了 2.0,主要是增加了 Queue,用于在一台机器上建立一个 Job 队列,可以同时在一台机器上排上多个 Job,一个一个重启电脑,重装系统后执行测试脚本的特性;另一个就是晚上趁着没人的时候,自动根据数据库覆盖率(在哪些机器上运行过),跑测试的功能,所以界面也换成了夜间的风格。

新版本极大地提高了自动化功能,由测试人员编写好测试脚本,白天可以由测试人员自己提交 Job 在不同的机器上执行并实时观测运行过程,晚上下班后程序也会将那些在一些机器上没有跑过的测试执行一遍,最终做到每一个测试脚本在所有的机器上都执行一遍,以检查系统是否能够在不同类型的机器上稳定运行。

Create new job - virtLAB 2

另一个是用于手动测试的 TCMS(与 Testopia database schema 完全兼容的 Test Case Management  System),半年前将它撂下,现在又重新捡起来了,经过 VirtLAB 的磨砺,而且新版本里可以加表,所以我对这个代码进行了重构,使用了大量 Django 自身的特性,比如 ACL 和自带的 Admin Page。和 VirtLAB 一样,使用了 python-kerberos 做了个 Kerberos  的用户名密码验证。因为 Testopia 的数据表结构比较复杂,所以对整个 Models 进行了重构,用 ForeignKey 和 ManyToManyField 重新进行了组织,自行编写了 TimeAsTimeDeltaField 来处理 Test Case 的 Estimated Time。

UI 也经过丹青的重新设计,变得更加的方便、易用。

 

总之,是个脱胎换骨的版本。

 

明天,30 号就是正式内部使用的日子,svn 的版本号也相当吉利 2046。我们将正式用它来代替服役了很长时间的 Test Runner 和根本不成熟且有版权问题的 Testopia。

Execute test run - TCMS

下一步计划 - 更加地自动化:

VirtLAB 将对每台机器加上 Tag,以后选机器不用去看主机名了,只要选好自己需要的配制,比如要 Intel 的处理器啊,要超过 4G 内存啊,就可以自动根据所选条件,自动选择空闲的机器,最快速地完成需要完成的 Job。

TCMS 将进一步对代码进行重构,进一步 Django app 化,同时完成 Report,以及和外部程序沟通的功能,目前只能将 Failed 的 Case 用 File a bug 链接直接提交到 Bugzilla 上,下一步将和 VirtLAB 和 ATP 整合,直接在 TCMS 里操作 VirtLAB 里的测试脚本。

BTW: 前一端时间公司内部开始使用 Redmine 进行内部项目管理,这个用 Rails 编写的工具确实有很多独到的特性,可以看看。

 

Posted by K*K Thu, 29 Oct 2009 15:41:33 -0400


Django 的 Form 真的很好用。

Django 的 Form 表单真的很好用,完全把以往繁琐的表单操作完全抽象出来,成了一个独立的组件。

该系统的最大特色就是与模板无关,表单元素完全在一个文件里就可以定义好,以后也可以随时扩充,修改,很方便。

为了使用富文本编辑器我还使用了 InPlaceEditor,之所以用它是因为它基于强大的 TinyMCE 编辑器,同时提供了很好的 Ajax 支持,为了使用它我还使用了 django-tinymce,这个东西理论上应该找不到编译好的包,可以用 easy_install 安装(在 Fedora 10 里的 python-setuptools-devel 包里),总之就是怎么方便怎么来啦。 :-)

OK, Let's get start it.

在 app 目录里建立一个 forms 的目录,touch 一个 __init__.py,然后在其中写下 newapp.py 文件,如下内容:

from django import forms
from tinymce.widgets import TinyMCE
 
TYPE_CHOICES = [
    [1, 'Desktop Computer'],
    [2, 'Laptop'],
]
 
class NewProduct(forms.Form):
    name = forms.CharField()
    type_id = forms.ChoiceField(choices=TYPE_CHOICES)
    description = forms.CharField(widget=TinyMCE(mce_attrs={})

添加 View 里某个方法(比如 index)填上:

def index(request):
    from testproject.app.forms.newapp import NewProduct
    new_form = NewProduct()
    return render_to_response('testform.html', { 'new_form' : new_form })

然后改模板,类似如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.01//EN">
<html lang="en">
<head>
    <title>New Product</title>
</head>
<body>
   <h1>New Product</h1>
   <form action="." method="POST">
        {{ new_form.as_table }}
     <p><input type="submit" value="Submit"></p>
    </form>
</body>
</html>

够好用吧?一个 form 定义好以后直接使用 as_table 方法就可以转换成表格。

如果需要更多自定义参数,也可以像访问数据库一样直接调用 form class 里的属性,如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.01//EN">
<html lang="en">
<head>
    <title>New Product</title>
</head>
<body>
   <h1>New Product</h1>
   <form action="." method="POST">
        {{ new_form.name }}
        {{ new_form.type_id }}
        {{ new_form.description }}
     <p><input type="submit" value="Submit"></p>
    </form>
</body>
</html>
 

在 Django 的官方教程里,设计一个 form class 的 ChoiceField 使用的是 Tuple,而我这里经过试验,List 也是可以的,而之所以使用 List,是因为这样可以通过数据库,向 ChoiceField 里添加数据,如:

from django import forms
from tinymce.widgets import TinyMCE
from testproject.app.models import ProductTypes
 
types = ProductTypes.objects.all()
TYPE_CHOICES = []
for type in types:
    TYPE_CHOICES.append([type.id, type.name])
 
class NewProduct(forms.Form):
    name = forms.CharField()
    type_id = forms.ChoiceField(choices=TYPE_CHOICES)
    description = forms.CharField(widget=TinyMCE(mce_attrs={})

嘿嘿,基本到此,还是比较简单的,附带一个我的 TinyMCE 的设置作为结尾好了。

from django import forms
from tinymce.widgets import TinyMCE
from testproject.app.models import ProductTypes
 
types = ProductTypes.objects.all()
TYPE_CHOICES = []
for type in types:
    TYPE_CHOICES.append([type.id, type.name])
 
class NewProduct(forms.Form):
    name = forms.CharField()
    type_id = forms.ChoiceField(choices=TYPE_CHOICES)
    description = forms.CharField(widget=TinyMCE(mce_attrs={'theme' : "advanced",
                                                            'skin' : "o2k7",
                                                            'skin_variant' : "silver",
                                                            'elements' : 'elm3',
                                                            'mode' : 'textareas',
                                                            'theme_advanced_toolbar_location' : "top",
                                                            'theme_advanced_toolbar_align' : "left",
                                                            'theme_advanced_resizing' : 'true',
                                                            'plugins' : "safari,pagebreak,style,layer,save,iespell,xhtmlxtras",
                                                            'theme_advanced_buttons1' : "fontselect,fontsizeselect,|,cut,copy,paste,pastetext,|,bullist,numlist,|,undo,redo,|,link,unlink",
                                                            'theme_advanced_buttons2' : "",
                                                            'theme_advanced_buttons3' : "",
                                                           })

不知道 Rails 或者其它 Web Framework 是否也有比较优秀的特色功能,希望也能有人能够介绍一下。

Posted by K*K Thu, 25 Dec 2008 16:44:13 -0400


一个 Django 的超简单的数据库应用

 昨天 Launch & Learn 的时候,做了个简单的 Django 的数据库应用,以配合 Li Li Zhang 的 ORM Course。

其实用 Django 做数据库应用真的很简单,不过比较适合用于重头设计的 Database Schema,然后用 syncdb 来同步数据库。

目前 Django 对 ForeignKey 和 One to One, One to Many, Many to Many 支持得都不错,最大的缺陷还是缺乏 Join 的支持导致多表联查的性能不好,这也是我在做开发的过程中碰到的最大问题。

其实用 Django 重头做一个数据库开发非常简单,用下面几步就可以了。

FIRST:
Create new project and a new app with django-admin.py
$ django-admin.py startproject [project_name]
$ cd [project_name]
$ django-admin.py startapp [app_name]

SECOND:
Edit the settings.py file to adjust db settings and installed apps.

THIRD:
Edit the [app_name]/models.py to modeling the database schema

FOURTH:
Edit the [prject_name]/urls.py to adjust the path of URL.

FIFTH:
Edit the [app_name]/views.py to realize your function.

SIXTH:
To run the manage.py to start the test server in the project.
$ ./manage.py runserver

THE END:
Use your browser to navigate to your http://localhost:8000 and enjoy in it. :-)

这里提供了一个范例,也是昨天在 Launch and Learn 上演示过的:www.box.net/shared/6036abumgv 中的 lnl.tar.bz2 文件,里面提供的 Steps 其实就是上面那段,只是代码中也提供了注释以方便阅读。

Posted by K*K Thu, 11 Dec 2008 10:05:38 -0400


scribes 编辑器,不错,不错

自定义了很多 HTML 标签,总算用起来比较顺手了。

稍后把 javascript、python 和 css 的 templates 都完善一下,就发上来。

最好用这个地址看:

http://www.youtube.com/watch?v=0IbUjO3J64c&fmt=18

Posted by K*K Wed, 29 Oct 2008 14:17:00 -0400


没事对三个 Web Framework 的 Mail-list 数量也做个比较

Mail-list count of Rails, Django and TurboGears

结果是:TurboGears 真的没人用了吗。。。

Posted by K*K Fri, 10 Oct 2008 10:58:00 -0400


Django 和 TurboGears ORM 性能测试完成

连续插入、查询、更改、删除 1000 个记录的测试,其实 ORM 比起在 MySQL 里直接执行真的慢多了(我的代码也得进一步优化)。。。

Django:

Django ORM performance test

TurboGears:

TurboGears ORM(SQLObject) performance test

下载在:http://www.box.net/shared/877kl03ht7

可以看出 Django 在 Insert 和 Select 动作上速度比较快,而在 Update 和 Drop 上稍慢一些。

这是因为 TurboGears SQLObject 提供了一个 get 方法可以直接获取数据库中对应 id 号的字段,而在做 DROP 操作时我使用了 clearTable 来直接清空表,而 Django 是一条条查询,一条条 delete。

总体上我还是对 Django 的性能比较满意的,这帮人在性能上的优化很 BT ...

PS: 下午给 SQLAlchemy 也做了个简单测试,还没搞明白怎么回事,执行 1000 次插入数据,结果实际只插入了一条,查询语句也有问题,不过性能已经能用”惨不忍睹“来形容了。

如下:

Insert Speed: 0.176656007767
Select Speed: 0.0367720127106
Update Speed: 0
Drop Speed: 0

Posted by K*K Thu, 09 Oct 2008 17:46:00 -0400


在 Mac OS X 上为 Django 安装 MySQL-python 1.2.2

在 Mac OS X 上安装 MySQL-python 花了一点点功夫, 记一下:

先去 Sun 网站上下载最新版本的 MySQL, 再去 djangoproject.org 上下载最新版本的 Django 1.0 release, 并且正常安装.

然后用 easyinstall mysql-python, 发现无法正常安装.

查看 easyinstall 的下载路径, 用下面的命令下载并且解压缩

$ cd /tmp
$ curl -o MySQL-python-1.2.2.tar.gz http://internap.dl.sourceforge.net/sourceforge/mysql-python/MySQL-python-1.2.2.tar.gz
$ tar xvf MySQL-python-1.2.2.tar.gz
$ cd MySQL-python-1.2.2

然后修改 site.cfg, 修改下面内容:

#mysql_config = /usr/local/bin/mysql_config

改成
mysql_config = /usr/local/mysql/bin/mysql_config

否则会出现找不到 MySQL config 的问题:
...
  File "/tmp/easy_install-nHSsgl/MySQL-python-1.2.2/setup_posix.py", line 24, in mysql_config
EnvironmentError: mysql_config not found


然后修改 _mysql.c, 把第 37 到 39 行注释掉, 如下:
//#ifndef uint
//#define uint unsigned int
//#endif

否则会出现:
In file included from /usr/local/mysql/include/mysql.h:47,
                 from _mysql.c:40:
/usr/include/sys/types.h:92: error: duplicate 'unsigned'
/usr/include/sys/types.h:92: error: two or more data types in declaration specifiers
error: command 'gcc' failed with exit status 1

然后再用 python ./setup.py build 编译
$ python ./setup.py build
running build
running build_py
copying MySQLdb/release.py -> build/lib.macosx-10.5-i386-2.5/MySQLdb
running build_ext
building '_mysql' extension
gcc -fno-strict-aliasing -Wno-long-double -no-cpp-precomp -mno-fused-madd -fno-common -dynamic -DNDEBUG -g -Os -Wall -Wstrict-prototypes -DMACOSX -I/usr/include/ffi -DENABLE_DTRACE -pipe -Dversion_info=(1,2,2,'final',0) -D__version__=1.2.2 -I/usr/local/mysql/include -I/System/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5 -c _mysql.c -o build/temp.macosx-10.5-i386-2.5/_mysql.o -g -Os -arch i386 -fno-common -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT
gcc -Wl,-F. -bundle -undefined dynamic_lookup -arch i386 -arch ppc build/temp.macosx-10.5-i386-2.5/_mysql.o -L/usr/local/mysql/lib -lmysqlclient_r -lz -lm -lmygcc -o build/lib.macosx-10.5-i386-2.5/_mysql.so
ld: warning in build/temp.macosx-10.5-i386-2.5/_mysql.o, file is not of required architecture
ld: warning in /usr/local/mysql/lib/libmysqlclient_r.dylib, file is not of required architecture
ld: warning in /usr/local/mysql/lib/libmygcc.a, file is not of required architecture

然后再用 python ./setup.py install 安装
$ sudo python ./setup.py install
Password:
running install
running bdist_egg
running egg_info
writing MySQL_python.egg-info/PKG-INFO
writing top-level names to MySQL_python.egg-info/top_level.txt
writing dependency_links to MySQL_python.egg-info/dependency_links.txt
reading manifest file 'MySQL_python.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'MySQL_python.egg-info/SOURCES.txt'
installing library code to build/bdist.macosx-10.5-i386/egg
running install_lib
running build_py
copying MySQLdb/release.py -> build/lib.macosx-10.5-i386-2.5/MySQLdb
running build_ext
creating build/bdist.macosx-10.5-i386
creating build/bdist.macosx-10.5-i386/egg
copying build/lib.macosx-10.5-i386-2.5/_mysql.so -> build/bdist.macosx-10.5-i386/egg
copying build/lib.macosx-10.5-i386-2.5/_mysql_exceptions.py -> build/bdist.macosx-10.5-i386/egg
creating build/bdist.macosx-10.5-i386/egg/MySQLdb
...

然后用下面的命令进行测试:
$ cd ~
$ python
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb
>>> MySQLdb.apilevel
'2.0'
>>> import django
>>> print django.VERSION
(1, 0, 'final')


如果能正常输出就没有问题了 :-)

Posted by K*K Wed, 17 Sep 2008 00:22:00 -0400