用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>

HuangYi/GenerateStaticPage (last edited 2009-12-25 07:14:14 by localhost)