自动加载主要用于开发和测试阶段,要不每次修改,都重启tornado服务,太囧。
tornado源码有autoreload模块。参考:autoreload.py
可以看到一个私有方法:_reload_on_update,其实只要引入这个模块,调用它即可。示例如下:
import tornado.autoreload def main(): server = tornado.httpserver.HTTPServer(application) server.listen(8888) instance = tornado.ioloop.IOLoop.instance() tornado.autoreload.start(instance) instance.start()
这样还是很麻烦,或者通过option参数来选择是否autoreload。偶然查看其 web.py 1000多行有这么一句:
# Automatically reload modified modules if self.settings.get("debug") and not wsgi: import autoreload autoreload.start()
这个是读取Application里settings是否有debug变量,有则调用autoreload。简化后代码如下:
settings = {'debug' : True} application = tornado.web.Application([ (r"/", MainHandler), ], **settings) def main(): server = tornado.httpserver.HTTPServer(application) server.listen(8888) tornado.ioloop.IOLoop.instance().start()
每一天都在前行的路上,而这一年似乎去的特别的快,特别的短暂。
一年的时间辗转三个城市,从南京到杭州,再到上海。一切的一切似乎都是昨天,那般的清晰。
其实很早就想离开工作快五年的公司,只不过是自己一直下不了决心。性格和患得患失一直左右着自己的思绪。时间的流逝,青春不再,或许再过些时间,或许什么都不是了。
偶然的机会,很荣幸的进入淘宝工作。能够从自己的小圈子走出来,去接触外面的世界。短短的几个月中,成长的内容明显的超过了前几年的积累。这不仅仅是技术的成长,更多的是人,是视野,是想法。这一切的一切,都得感谢淘宝的师兄和主管。回想前几年,自己的世界里只有去完成一些事情,而现在更多的是应该觉得自己主动解决一些事情。当然,沟通上面来的更为明显。程序久了,思维的方式都会定死,而接触其他的岗位,去了解他们人的思路和想法,很多思绪都会豁然开朗。
杭州之行匆匆而逝,来到了大上海,这个充满魔力和摩登的都市。说真的,自己尚未体会。换了新环境,适应是必须的。在试用期内很快直接切入项目,几个月很快过去了。虽然在一些问题上自己不能决定什么,但是还是很幸运,可以从项目最初的雏形,到现在已经测试发布,自己都在其中。其实这个正是自己所擅长的。我想的就是自己能够决定更多,能够参与的更多,当然,或许这个可能性还需要自己去努力,或许现实总是那般无力,或许。
一年的流水账,想说,并不容易。希望自己一直能够如此前行,走自己的路,知道自己需要什么,能够得到什么。足矣。
零点的钟声已过,回忆这一年,许许多多的人,给了自己很多很多的帮助,感谢一下。
何伟平:很感谢何老师的推荐,才能有机会进入淘宝这样的大公司。何老师的谦虚和热心,很值得自己去学习。很遗憾,至今未有机会请何老师吃顿饭。 康伯:在淘宝时候我的主管。很感谢他跟自己多次的交流,有想法就说,就交流。给了自己很多机会。他是我至今为止唯一一个在系统方面很膜拜的人。 大舞:淘宝入职时候的师兄。试用期内给了自己很多建议和指导,一个很帅很帅的男人。@kemin_ukl 春哥:非芒果台的那位。感谢春哥推荐了自己来盛大,还混了不少饭,春哥工作和生活的太多很值得码农学习和借鉴。@mcspring 道神:灰常牛叉的DD,感谢刚来魔都时候收留了俺这个码农。回头还要多搭讪,求其在Debian方面的经验。@lidaobing 群众:鄙人群里那些哥们,你们都是神一样的男人!因为有了你们,才有了欢乐!@marchliu @xiaoxiaolu @guangfengio 等等大牛们。
话不多说,祝愿那些把帮助和关心过我的人,新年能够身体健康,幸福快乐!
去迎接新的一年,我,继续在路上。
杂谈一下,我不是搞产品的也不是搞技术的,只是一个打杂的。随便扯谈一下。
作为一个产品,既然有这个名称,必定有其定位。在构思之前,就必须有明确的针对人群。比如是针对年轻人(80、90),抑或者上班族等等。模糊与笼统的定位,带来的只是无谓的“探索”。定位不是靠摸索出来的,也不是磨打出来的,是在你的脑海里,在你的产品里。即使现在模仿风气如此浓厚的时候,需要的也是定位。你的定位在哪儿,注定成就怎样的结果。
有了想法,下面就是一些调查和思考。你的这些针对人群在你的产品你会喜欢什么,会怎样的习惯?这个时候需要做的就是多和你的目标与非目标受众多去聊天,多去发觉他们的喜好与需求。或许你的改动只在某时一句话。所谓的走出去,这一步是必须的。闭门造车,最后可能出来就是一个自个儿意淫的杯具。
初期的实现与原型。很多时候喜欢在白板或者纸上写点什么,画点什么。记住!这一些都不能丢弃,或者擦掉。或许只是一些顺手涂鸦,或者解乏的简笔画。原型设计不需要一个完整的流程图,应该突出其顺序和关键点,以及部分UI的展示。这个过程中可以适当让受众面参与进来,设计出非自己主观的思路。
好吧,其实这些过程是可以修改和整合的。毕竟咱写的是互联网应用,不会给你完整的需求文档,完整的流程图,那样还叫互联网么?那是外包(无贬义,含笑)。
到现在为止应该糅合一些技术的关键字,比如哪些可以做到,哪些比较复杂。哪些技术可取,哪些可以折中。在考虑这个阶段的时候,技术人员需要的更多的是倾听,而不是纠结在某个环节,或者抵制某些习惯与思路。你可以说下自己的观点与想法,但是记住这些只是你自己的主观出发点,代表不了什么(如果正好受众面就是你,那恭喜了!)。需要做的就是记录下需求,转为脑海中虚拟的实现与流淌。一切心中有谱之后,可以适当“讨价还价”。毕竟每个人说出的都是自己的想法。
该画出流程图了。和上面原型一样,记住,别随意擦掉。用小人也可以,用箭头也可以,或者圆圈。你描述的只是过程,不是漫画和小说。当然加上这些元素会显得你的设计更加有爱。流程图的初衷在于走通整个流程,以及画出关键点。大致抽象出各个模型、结构和交互情况。适当写些文档把,这个总没有坏处的。或许这就是设计文档的初稿。
选型。有了需求,有了流程。下面当然是选择怎么去实现。说到用什么,仁者见仁,智者见智。啥好?啥不好?不是道听途说。关键在于自己。这些年来,喜欢的一句话就是:用自己熟悉的、用自己顺手的。看看外面的世界,好东西太多了,难不成有兴趣什么都来用一下?清醒吧哥们。你不是科学家,不是搞研究的。有这个时间,完全可以把你自己熟悉的搞的更透彻。这里并不是抵制新的或者好的工具,要明白一点,这些工具的作用域在哪儿,如果对自己实在可能起不到啥作用,或者只是存在你的假想中,放放把。未来再尝试也不迟。
关键点的实现与雏形。套句时髦的话,这个是不是应该算架构和设计?抽象出大致的模块,划分出结构。不必太在意其完整性和准确性,只要能走通就好。一次都给你写完了,其他人都去喝茶看报纸?雏形嘛,你懂得。当然,还得明确具体的工具,比如语言、数据库、系统等等。一个准则:用自己熟悉的,外加一条:简单就好。
是不是有了大体的架子了?可能下面就是大工作量的体力活啦。当然,分配体力活也是一个很体力的事情。没有一个好的管理者,这个产品就是大家拆东墙补西墙,互相推诿的产物。大致的职责有:传承需求和变化,分配与监察。消化和理解需求,确实是个跟天赋有关的事情,如果都是一个顺序跑下来的,那也不叫互联网了。需要很好的沟通能力,纸面或者口头的描述,随时可能千变万化,一成不变,继续去做外包把(囧)。分配这个环节就跟经验有关了,多去发觉你团队中的兴趣与擅长,用其长处,适当补短。合适的人干合适的事情,嘛效率?这就出来了。大家都在干活,进度就需要自己不断的监控与调整,适当多给自己宽裕的时间,哪怕只是那么一两小时。凡事没绝对,多想,多看,总是对的。
实现。设计数据库,写类库,写页面。详细罗列的话估计一长串。然后就是拆分逻辑,拆分页面,拆分功能点,然后就是与之对应的整合和补充。说到这边,可能就有人会说,用某某类库,或者某某框架,某某工具。这一切都建立在对其了解的基础上。不要太迷信,同样的刀在不同人手上是不一样的,用的好才是好刀,用不好连茅草都不如。折腾的滋味自己尝把。不是用了啥就牛逼,而是解决了啥,针对性的解决才是牛逼的关键。所有的一切,都只不过是实现的一种手段。条条大路,都可以。不要太迷信××,那只是一个传说。没有万能的实现,只有不断的解决与重新审视。实现细节滤过。。。
测试。不是写几个TestCase就是测试,那个只是证明你的代码看起来没啥问题,当然也不仅仅是用了啥测试框架,多专业。都只是辅助工具。除去功能性的测试,需要的是注意细节上。如果仅仅只是能用,没错没bug。这个不是产品,或许就是留言版。当然应该提供更多的可用性、流畅性以及体验。
唉,一不小心快十二点了,洗洗睡吧。未完再补充。
前面几篇教程简单讲述了如何使用 Pylons 进行 WEB 方面开发的步骤,包括简单的 Hello、表单和数据库操作等内容。本篇将描述一下如何在正式环境中发布基于 Pylons 的 WEB 应用。
测试环境:Nginx 0.8.53 + FastCGI 模式 (需要安装 flup 模块)
pip install flup # easy_install -U flup
测试代码,延用前面的 Hello 示例。
mac:python smallfish$ paster create -t pylons hello mac:python smallfish$ cd hello/ mac:hello smallfish$ paster controller hi mac:hello smallfish$ paster serve --reload development.ini
确保以上过程无错,访问:http://127.0.0.1:5000 可以看到默认页面。
好把,开始配置发布环境。
需要修改 development.ini 配置文件,找到 [server:main] 节点,修改其中的 use 方式(默认是 egg:Paste#http)。
[server:main] use = egg:PasteScript#flup_fcgi_thread host = 0.0.0.0 port = 5000
另外建议修改 [DEFAULT] 节点中 debug = false,以免错误会打印具体的环境和堆栈信息。
到这里 Pylons 部分以及设置好了,如果出现一下错误:
LookupError: Entry point 'flup_fcgi_thread' not found in egg 'Paste'
请注意上面的 use 部分里是 PasteScript 而不是 Paste哦。淡定淡定,别光看后面的 http 改成 flup_fcgi_thread。
下面修改 Nginx 的配置 nginx.conf,修改其中 / 部分设置。
location / { fastcgi_pass 127.0.0.1:5000; fastcgi_index index; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; include fastcgi_params; fastcgi_intercept_errors off; }
其中 fastcgi_pass 中 host 和 port 对应 development.ini 中的配置。
好把,这里可以启动,看看是否正确,请注意相应的目录。
启动 Pylons 部分(启动 daemon 进程,或参考搜狐邮箱使用的 zdaemon 来管理进程):
mac:hello smallfish$ paster serve --reload development.ini --daemon start # 注意,正式环境中请去除 reload 参数 # daemon 后面参数有 start | stop | restart | status,可以很方便的管理进程
启动 Nginx 部分:
mac:~ smallfish$ sudo /opt/nginx/sbin/nginx
尝试一下访问: http://localhost/ 和 http://localhost/hi/index 。是不是都可以了?OK,到这里已经整合好了。
这里是采用 FastCGI 方式发布,当然还可以用默认 http 或者本地 socket 方式,然后通过 proxy_pass 方式转发过去也是可以的。
当然,这个只是简单示例,可能正式发布时候需要注意的事项比这个复杂的多。这里只是介绍一种方式而已。
希望通过这一系列的教程,希望能对喜欢 Python 和关注 Pylons 框架的朋友能有所帮助。
前几篇链接分别如下:
1. Pylons 入门实例教程 – Hello
2. Pylons 入门实例教程 – 表单和文件上传
3. Pylons 入门实例教程 – 数据库操作
4. Pylons 入门实例教程 – cookie 和 session
现在满地都是KV数据库的文字,PostgreSQL 也有类似的结构。不过是通过其强大的扩展方式实现的。
官网文档请参考:http://www.postgresql.org/docs/current/static/hstore.html
本文测试环境在 Mac OS 下,Pg采用源码编译。
编译 hstore 扩展
mac:~ smallfish$ cd Downloads/postgresql-9.0.1/contrib/hstore/ mac:hstore smallfish$ make ... 一堆编译信息 mac:hstore smallfish$ sudo make install
导入到数据库中,注意必须以 postgres 用户,如果需要装入到指定数据库,请指明。这里采用默认数据库。
mac:hstore smallfish$ ls /opt/postgresql/share/contrib/ hstore.sql uninstall_hstore.sql mac:hstore smallfish$ psql -U postgres -f /opt/postgresql/share/contrib/hstore.sql ... 一堆导入命令
进入数据库,建一个测试表
postgres=# CREATE TABLE testhstore (id SERIAL, value hstore); NOTICE: CREATE TABLE will create implicit sequence "testhstore_id_seq" for serial column "testhstore.id" CREATE TABLE
查看下表结构
postgres=# \d List of relations Schema | Name | Type | Owner --------+-------------------+----------+---------- public | testhstore | table | postgres public | testhstore_id_seq | sequence | postgres (2 rows) postgres=# \d testhstore; Table "public.testhstore" Column | Type | Modifiers --------+---------+--------------------------------------------------------- id | integer | not null default nextval('testhstore_id_seq'::regclass) value | hstore |
尝试下简单 hstore类型
postgres=# select 'a=>1, b=>2'::hstore; hstore -------------------- "a"=>"1", "b"=>"2" (1 row) postgres=# select 'a=>1, b=>a'::hstore; hstore -------------------- "a"=>"1", "b"=>"a" (1 row)
写几条测试数据先
postgres=# INSERT INTO testhstore (value) VALUES ('name=>smallfish, age=>29'::hstore); INSERT 0 1 postgres=# SELECT * FROM testhstore; id | value ----+---------------------------------- 1 | "age"=>"29", "name"=>"smallfish" (1 row) postgres=# INSERT INTO testhstore (value) VALUES ('name=>nnfish, age=>20'::hstore); INSERT 0 1 postgres=# INSERT INTO testhstore (value) VALUES ('name=>aaa, age=>30, addr=>China'::hstore); INSERT 0 1
查看下所有数据
postgres=# SELECT * FROM testhstore; id | value ----+--------------------------------------------- 1 | "age"=>"29", "name"=>"smallfish" 2 | "age"=>"20", "name"=>"nnfish" 3 | "age"=>"30", "addr"=>"China", "name"=>"aaa" (3 rows)
查询列里面的指定 key
postgres=# SELECT id, value->'name' AS name FROM testhstore; id | name ----+----------- 1 | smallfish 2 | nnfish 3 | aaa (3 rows) postgres=# SELECT id, value->'name', value->'age' AS age FROM testhstore; id | ?column? | age ----+-----------+----- 1 | smallfish | 29 2 | nnfish | 20 3 | aaa | 30 (3 rows)
修改列某 key 值
postgres=# UPDATE testhstore SET value=value||('addr=>Shanghai') WHERE id = 2; UPDATE 1 postgres=# SELECT * FROM testhstore; id | value ----+--------------------------------------------------- 1 | "age"=>"29", "name"=>"smallfish" 3 | "age"=>"30", "addr"=>"China", "name"=>"aaa" 2 | "age"=>"20", "addr"=>"Shanghai", "name"=>"nnfish" (3 rows)
删除列里某 key
postgres=# UPDATE testhstore SET value=delete(value, 'addr') WHERE id = 3; UPDATE 1 postgres=# SELECT * FROM testhstore; id | value ----+--------------------------------------------------- 1 | "age"=>"29", "name"=>"smallfish" 2 | "age"=>"20", "addr"=>"Shanghai", "name"=>"nnfish" 3 | "age"=>"30", "name"=>"aaa" (3 rows)
按条件查询列里某 key ,注意要数据类型,CAST 强转。默认都是字符串的值。
postgres=# SELECT * FROM testhstore WHERE (value->'age')::INT > 20; id | value ----+---------------------------------- 1 | "age"=>"29", "name"=>"smallfish" 3 | "age"=>"30", "name"=>"aaa" (2 rows) postgres=# SELECT * FROM testhstore WHERE value->'name' = 'smallfish'; id | value ----+---------------------------------- 1 | "age"=>"29", "name"=>"smallfish" (1 row)
目的是想在服务器端生成某个网页的缩略图。Google了好久,发现一个好开源东西:CutyCapt。
系统:CentOS 5.5
官网:http://cutycapt.sourceforge.net/
依赖:QT http://www.qtsoftware.com/
附缩略163.com图,虽然说字体渲染的效果一般,但是看起来还凑合
首次是在Debian下测试的,很顺利。换了CentOS不是太爽。具体安装和使用步骤如下:
1. 下载RPM包
(64位) wget http://dl.atrpms.net/el5-x86_64/atrpms/testing/qt44-4.4.3-10_4.el5.x86_64.rpm wget http://dl.atrpms.net/el5-x86_64/atrpms/testing/qt44-x11-4.4.3-10_4.el5.x86_64.rpm wget http://dl.atrpms.net/el5-x86_64/atrpms/testing/qt44-devel-4.4.3-10_4.el5.x86_64.rpm (32位) wget http://ftp.riken.go.jp/Linux/atrpms/el5-i386/atrpms/testing/qt44-4.4.3-10_4.el5.i386.rpm wget http://ftp.riken.go.jp/Linux/atrpms/el5-i386/atrpms/testing/qt44-x11-4.4.3-10_4.el5.i386.rpm wget http://ftp.riken.go.jp/Linux/atrpms/el5-i386/atrpms/testing/qt44-devel-4.4.3-10_4.el5.i386.rpm
2. 安装 qt-devel 依赖包
yum install libXi-devel yum install libXinerama-devel
3. 安装 qt 相关
rpm -ivh qt44-4.4.3-10* rpm -ivh qt44-x11-4.4.3-10* # rpm -e qt-devel --nodeps --allmatches rpm -ivh qt44-devel-4.4.3-10*
4. 修改 /etc/profile,最后并:source /etc/profile
export QTDIR=/usr/lib64/qt44 export QTLIB=/usr/lib64/qt44/lib export QTINC=/usr/lib64/qt44/include export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH export PATH=$QTDIR/bin:$PATH
5. 安装 cutycapt
svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt mv cutycapt/CutyCapt /usr/local/CutyCapt cd /usr/local/CutyCapt qmake make
6. 安装模拟 x-server 服务端
wget http://www.flexthinker.com/wp-content/uploads/2009/11/xvfb-run.sh.txt mv ./xvfb-run.sh.txt /usr/local/CutyCapt/xvfb-run.sh chmod u+x /usr/local/CutyCapt/xvfb-run.sh
7. 开始欢快的截图吧
/usr/local/CutyCapt/xvfb-run.sh --server-args="-screen 0, 1024x768x24" /usr/local/CutyCapt/CutyCapt --url=http://www.163.com --out=163.jpg
8. 如果看不到汉字或乱码,需要安装chinese字体
yum install fonts-chinese
9. 由于截屏的是整个网站的页面,只需要第一屏幕
convert -crop 1024x768+0+0 163.jpg 1632.jpg
10. 缩小图片
convert -resize 40%x40% 1632.jpg 1632.jpg
PPT下载地址: Python Story.ppt
http://www.slideshare.net/nnfish/python-story
很荣幸收到龙哥 @hoorace 邀请去参加了杭州第四期程序员圆桌会议,顺带介绍了下最近在公司内部做的关于《Pythonic》分享。喜欢Python的可以下载看看把。
收获还是颇丰,多接触了点其他工种的朋友。
话题比较宽泛,基本我就是纯酱油飘过。感谢网新的朋友做的Vim的分享,另外威猛的升哥topic也不错,对RedHat系统安装和启动加载有了更多的了解。
另外很遗憾的就是威大师竟然没说点啥,可惜了那么好的水果茶啊。。。残念残念。。
本篇讲述在 Pylons 里使用 cookie 和 session。
示例还是在上篇《Pylons 入门实例教程 – 数据库操作》的代码里继续添加。先来尝试下 cookie,添加新的 cookietest controller。
修改 index 方法,添加显示部分:
def index(self): name = 'NULL' if request.cookies.has_key('name'): name = request.cookies['name'] return 'cookie name=%s' % name
cookie 读取可以通过 request.cookies 对象,类似一个字典结构。需要注意的是读取时候用最好 has_key 判断下,这样避免抛 KeyError 异常。当然你也可以 try…catch 捕获一下。
再重新写一个方法,用来写 cookie。
def writecookie(self): response.set_cookie("name", "smallfish") return "write cookie ok"
这里只是简单设置一个值得,set_cookie 还有其他参数,具体如下:
set_cookie(self, key, value='', max_age=None, path='/', domain=None, secure=None, httponly=False, version=None, comment=None, expires=None, overwrite=False)
基本一般需要设置:max_age,path,domain,expires 这几个参数。
下面再来尝试一下 session:
smallfish@debian:~/workspace/python/hellodb$ paster controller sessiontest Creating /home/smallfish/workspace/python/hellodb/hellodb/controllers/sessiontest.py Creating /home/smallfish/workspace/python/hellodb/hellodb/tests/functional/test_sessiontest.py
和上面 cookie 例子类似,在 controller 里有两个方法,index 负责显示 session,writesession 负责写。
def index(self): name = session.get('name', 'NULL') return 'session name=%s' % name def writesession(self): session['name'] = 'smallfish' session.save() return "save session ok"
index 方法里 get 后面的 NULL 是默认值。writesession 里需要注意下设置 session 之后需要 save。
删除 session 可以尝试如下:
del session['name'] # 删除所有 session.delete()
到这里,WEB 常用的一些东西在 Pylons 里基本走了一圈,包含 URL、模板、数据库和会话部分。
下一节将会涉及怎么在 Nginx 上发布 Pylons 应用。
前面两篇入门,讲述了 Pylons 大致开发的流程、表单以及文件上传,思路大致跟传统的开发类似。本篇简单讲述下在 Pylons 如何使用数据库。
本篇侧重点是使用 ORM 框架 SQLAlchemy。现在 Python 社区里关注度比较高的大概有三:SQLAlchemy、SQLObject 和 Storm。其实本人最早是研究了一下 Storm,后来听虾哥(@marchliu)在应用里不是很爽之,遂关注了下他推荐的 SQLAlchemy。当然,你也可以对应数据库的 DB-API 库来进行操作。
示例代码的数据库是 PostgreSQL,对应的 Python 库使用的是 psycopg2。至于 Pg 配置和使用这里不再累赘,请狗之。
Debian/Ubuntu 安装很简单:
sudo aptitude install python-psycopg2
建立一个测试数据库,比如 test:
smallfish@debian:~/workspace/python/hello$ su postgres postgres@debian:/home/smallfish/workspace/python/hello$ createdb -O smallfish test postgres@debian:/home/smallfish/workspace/python/hello$ exit smallfish@debian:~/workspace/python/hello$ psql -h 127.0.0.1 -p 5432 -U smallfish test 用户 smallfish 的口令: psql (8.4.4) SSL连接 (加密:DHE-RSA-AES256-SHA,位元:256) 输入 "help" 来获取帮助信息. test=#
数据库的部分已经OK,下面就是来倒腾 Pylons 啦。
建立新项目,加入支持数据库部分,注意 Enter sqlalchemy那个选项,默认是 False,改成 True:
smallfish@debian:~/workspace/python$ paster create -t pylons hellodb Selected and implied templates: Pylons#pylons Pylons application template Variables: egg: hellodb package: hellodb project: hellodb Enter template_engine (mako/genshi/jinja2/etc: Template language) ['mako']: Enter sqlalchemy (True/False: Include SQLAlchemy 0.5 configuration) [False]: True Creating template pylons Creating directory ./hellodb
改成 True 之后在自动生成的 development.ini 里就有对应的数据库配置选项了。
再建立新的 db controller:
smallfish@debian:~/workspace/python$ cd hellodb/ smallfish@debian:~/workspace/python/hellodb$ paster controller db Creating /home/smallfish/workspace/python/hellodb/hellodb/controllers/db.py Creating /home/smallfish/workspace/python/hellodb/hellodb/tests/functional/test_db.py
编辑 development.ini,添加数据库配置部分。smallfish:123456 是对应的 PostgreSQL 用户名/密码,127.0.0.1:5432 是对应的主机地址/端口号,最后的test则是数据库名。
# SQLAlchemy database URL sqlalchemy.url = postgresql://smallfish:[email protected]:5432/test
编辑 hellodb/model/__init__.py,加上一个叫 msg 的表和字段的定义:
"""The application's model objects""" from hellodb.model.meta import Session, metadata from sqlalchemy import orm, schema, types from datetime import datetime def init_model(engine): """Call me before using any of the tables or classes in the model""" Session.configure(bind=engine) def now(): return datetime.now() msg_table = schema.Table('msg', metadata, schema.Column('id', types.Integer, schema.Sequence('msg_seq_id', optional=True), primary_key=True), schema.Column('content', types.Text(), nullable=False), schema.Column('addtime', types.DateTime(), default=now), ) class Msg(object): pass orm.mapper(Msg, msg_table)
示例 Msg 表很简单,三个字段:ID、内容和时间。
上面的代码除去导入 sqlclchemy 包里几个库,基本上有一个对应表的字段定义,还有一个空的 Msg 对象。
最后一行,则是做一个 map 的动作,把 Msg 映射到 msg_table 上。
下面是不是要在数据库里建立对应的表呢?有个简单的办法 可以初始化数据库:paster setup-app development.ini:
smallfish@debian:~/workspace/python/hellodb$ paster setup-app development.ini Running setup_config() from hellodb.websetup 20:08:43,619 INFO [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] select version() 20:08:43,619 INFO [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] {} 20:08:43,625 INFO [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] select current_schema() 20:08:43,625 INFO [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] {} 20:08:43,631 INFO [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] select relname from pg_class c join pg_namespace n on n.oid=c.relnamespace where n.nspname=current_schema() and lower(relname)=%(name)s 20:08:43,631 INFO [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] {'name': u'msg'} 20:08:43,637 INFO [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] CREATE TABLE msg ( id SERIAL NOT NULL, content TEXT NOT NULL, addtime TIMESTAMP WITHOUT TIME ZONE, PRIMARY KEY (id) ) 20:08:43,637 INFO [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] {} 20:08:43,732 INFO [sqlalchemy.engine.base.Engine.0x...854c] [MainThread] COMMIT
可以看到上面的输出日志,包括了建表的SQL语句。其中 SERIAL 对应上面 __init__.py 里 Column 的 Seq 定义。serial 类型 在 PostgreSQL 可以看成类似 MySQL 的自增ID(auto_increment) 。
现在进入 PostgreSQL 查询数据库,就可以看到表以及序列已经建立。
test=# \d 关联列表 架构模式 | 名称 | 型别 | 拥有者 ----------+------------+--------+----------- public | msg | 资料表 | smallfish public | msg_id_seq | 序列数 | smallfish (2 行记录)
到这里,准备工作已经完毕,包括了初始化数据库,配置文件还有示例 controller。
下面就在 controller 代码里增加读写数据库的功能吧。
首先建立一个表单模板 db.htm ,用来添加并保存到数据库表中:
<form action="/db/add" method="post"> <input type="text" name="content" /> <br /> <input type="submit" value="save" /> </form>
对应 controller index 修改成,很简单。返回到模板:
class DbController(BaseController): def index(self): return render('/db.htm')
添加 add 方法,对应上面 form 中的 /db/add 路径:
def add(self): content = request.POST['content'] from hellodb import model msg = model.Msg() msg.content = content model.meta.Session.add(msg) model.meta.Session.commit() return "add %s ok..." % content
添加部分简单完成。获取 POST 文本框,然后初始化一个 Msg 对象(上面 model 里定义的)。
注意 add 之后,必须手动 commit,这样才会真正保存到数据库。
浏览器访问一下:http://127.0.0.1:5000/db/index,随意添加一点数据吧,这个时候你可以在 PostgreSQL 里查询已经数据已经加进来了。
下面在 index 方法传递一些值到模板,输出刚才已经添加的数据:
def index(self): from hellodb import model c.msgs = model.meta.Session.query(model.Msg).all() return render('/db.htm')
c.msgs 可以理解成全局变量,关于 c 的定义在 controller前几行就应该看到了。修改模板 db.htm 显示记录:
% for msg in c.msgs: <p>${msg.id}: ${msg.content} / ${msg.addtime}</p> % endfor
很简单,只是一个普通 for 循环,遍历 index 方式里传递的 c.msgs。Mako模板还是很易读的吧?
继续刷新下:http://127.0.0.1:5000/db/index,可以在页面上看到已经添加的数据了。
在狂输入了几十条之后,在一页里显示是不是忒土鳖了?
下面再介绍下 Pylons 里 webhelper 里一个分页组件的用法,当然你也可以自己写分页算法。下面是示例:
def list(self): from webhelpers import paginate from hellodb import model msgs = model.meta.Session.query(model.Msg) c.paginator = paginate.Page( msgs, page=int(request.params.get('page', 1)), items_per_page = 10, ) return render("/list.htm")
导入 paginate,然后把查询的数据库对象当参数传递给 paginate.Page,里面的page则是页面的传递的页数参数,items_per_page 就好理解多了,就是多少条一页。这里是10条。
对应的模板 list.htm 如下:
<pre> % if len(c.paginator): % for msg in c.paginator: <p>${msg.id}: ${msg.content}</p> % endfor <p> ${c.paginator.pager("count: $item_count $first_item to $last_item , $link_first $link_previous $link_next $link_last")} </p> % endif
for 部分如同上面示例,下面加了一行pager。里面一些变量从名字上就可以看出功能了。包括了总条数、当前是第几到第几条,然后就是常用的首页、上页、下页和最后一页。
这里链接的文字都是<<, <, >, >>。想改成文字请查看文档吧。。如果是第一页,是不会显示首页和上一页的。这个做过分页的一般都写过类似的代码吧。
现在访问:http://127.0.0.1:5000/db/list,想看到效果当然你得多填点数据哦。10条才会显示分页的挖。
好了,这里对数据库增加和显示部分都已经有示例代码了,当然最后还有一个分页用法。至于删除和更新之类请参考 SQLAlchemy 文档吧。