用python做静态文件生成程序
我想,给大家介绍python,并不是一定会再工作中用到,毕竟实际应用起来还是要考虑许多非技术的问题。主要是想让大家了解一点新东西吧。大家可以先看下这个,有兴趣的话分享的时候再介绍一些python的基本情况。python本身以及下面代码涉及到的库都是跨平台的,大家有兴趣的话可以直接在windows上试验了。以后要是真的投入实际应用,也可以在windows上开发调试,然后再拷到服务器上去执行。
生成静态文件的逻辑其实不复杂,无非加载数据,渲染模板。加载数据的时候需要做一些转换,过滤,分类,排序,分页等。渲染模板的时候也会有一些简单的逻辑。说起来很简单,但用c++实现起来却需要一大坨代码。用python可以少敲很多代码。
比如说生成全部歌手的页面。自然语言描述如下:
连接数据库 执行sql语句 select * from music.t_singer; 获取歌手数据 执行sql语句 select * from music.t_track; 获取歌曲数据 加载模板 渲染模板 写文件
现在来看下python代码:
1 # 导入 mysql 的库和模板类
2 import MySQLdb as dbapi
3 from mako.template import Template
4
5
6 # 连接数据库
7 connection = dbapi.connect(host="ip", port=port, user="...", password="...",database="...")
8 cursor = connection.cursor(dbapi.DictCursor) #默认fetchall返回的是tuple,类似列表,也就是只能用 0,1,2,3 这样访问,传递这个参数会可以返回 字段名:value 这样哈希表
9
10
11 # 加载数据
12 cursor.execute("select * from music.t_singer;")
13 singerlist = cursor.fetchall()
14 cursor.execute("select * from music.t_track")
15 songlist = cursor.fetchall()
16
17
18 # 转换数据
19 # 把 songlist 转换成以 singer id 为 key 的哈希表(c++叫map,python叫dict字典,javascript叫对象)方便查找。
20 songmap = defaultdict(list)
21 for song in songlist:
22 songmap[song['Fsinger_id']].append(song)
23
24
25 #加载模板
26 template = Template(filename="模板文件路径/singer_tpl.html")
27 for singer in singerlist:
28 # 循环渲染模板
29 content = template.render(singer=singer, songlist = songmap[singer['Fsinger_id']]])
30 file = open('目标路径/singer_%d.html' % singer.id, 'w')
31 #写文件
32 file.write(content)
33 file.close()
34
35
36 cursor.close()
37 connection.close()
关于错误处理,一般如果出错应该直接推出程序的就没必要去捕捉了,因为退出的时候,python本身会输出详细的异常信息,出错位置,和完整的backtrace。
"Errors should never pass silently. Unless explicitly silenced." -- zen of python
大家也可以看到渲染模板的时候只传一个 singer 对象进去,实际上在模板里面也是可以放一些简单的程序逻辑的,比如循环,比如获取对象的属性等,这也大大降低了主程序的复杂性。 另外下面的模板利用了模板继承的特性,可以把页面通用的部分(比如导航栏)做成一个父模板,子模板直接继承,同时又可以重写一部分父模板的内容(比如修改title)。
父模板(base_tpl.html):
<html> <head> <title>${self.title()}</title> ... <head> <body> <% menus = [ ('热门歌手', 'http://...'), ('热门歌曲', 'http://...'), ] %> <!-- 导航栏 --> <ul> % for menu in menus: % if menu[0] == self.attr.current_menu: <li class="now">${menu[0]}</li> % else <li><a href="menu[1]" title="menu[0]">menu[0]</a></li> % endif % endfor </ul> ${self.maincontent()} </body> </html>
子模板(singer_tpl.html):
<%inherit file="base_tpl.html"/> <%def name="title()"> 音乐商城-歌手${singer["Fsinger_name"]} </%def> <%! # 定义高亮显示的导航栏菜单 current_menu = "热门歌手" %> <%def name="maincontent()"> 歌手名:${singer["Fsinger_name"]} <br/> 歌手描述: ${singer["Fsinger_desc"]} 歌曲列表: <ul> % for song in songlist: 歌曲名:${song["Fsong_name"]} 。。。 % endfor </ul> </%def>