﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Read Sean-随笔分类-On Python</title><link>http://www.blogjava.net/sean/category/37361.html</link><description>Read me, read Sean.</description><language>zh-cn</language><lastBuildDate>Tue, 26 Jul 2011 21:12:20 GMT</lastBuildDate><pubDate>Tue, 26 Jul 2011 21:12:20 GMT</pubDate><ttl>60</ttl><item><title>pyPdf - 用Python方便的处理PDF文档</title><link>http://www.blogjava.net/sean/archive/2011/07/26/355089.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Tue, 26 Jul 2011 14:25:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2011/07/26/355089.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/355089.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2011/07/26/355089.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/355089.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/355089.html</trackback:ping><description><![CDATA[<br />
今天临时有个需求，那就是给某PDF文档切边，以方便在Kindle 3的6吋屏上阅读。<br />
<br />
很久没碰Python了，不过我相信用Python一定有办法解决这个需求，于是经过简单的googling，便发现了这个pyPdf库 (&nbsp;<a href="http://pybrary.net/pyPdf/" target="_blank">http://pybrary.net/pyPdf/</a>&nbsp;) ，操作起来相当直接易懂，把代码贴在这儿，做个记录。<br />
<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">from</span><span style="color: #000000; ">&nbsp;pyPdf&nbsp;</span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;PdfFileWriter,&nbsp;PdfFileReader<br />
</span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #000000; "><br />
</span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #000000; ">pdf&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;PdfFileReader(file(</span><span style="color: #800000; ">'</span><span style="color: #800000; ">original.pdf</span><span style="color: #800000; ">'</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #800000; ">'</span><span style="color: #800000; ">rb</span><span style="color: #800000; ">'</span><span style="color: #000000; ">))<br />
</span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; ">out&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;PdfFileWriter()<br />
</span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #000000; "><br />
</span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;page&nbsp;</span><span style="color: #0000FF; ">in</span><span style="color: #000000; ">&nbsp;pdf.pages:<br />
</span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;page.mediaBox.upperRight&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">580</span><span style="color: #000000; ">,</span><span style="color: #000000; ">800</span><span style="color: #000000; ">)<br />
</span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;page.mediaBox.lowerLeft&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">128</span><span style="color: #000000; ">,</span><span style="color: #000000; ">232</span><span style="color: #000000; ">)<br />
</span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;out.addPage(page)<br />
</span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #000000; "><br />
</span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #000000; ">ous&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;file(</span><span style="color: #800000; ">'</span><span style="color: #800000; ">target.pdf</span><span style="color: #800000; ">'</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #800000; ">'</span><span style="color: #800000; ">wb</span><span style="color: #800000; ">'</span><span style="color: #000000; ">)<br />
</span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #000000; ">out.write(ous)<br />
</span><span style="color: #008080; ">13</span>&nbsp;<span style="color: #000000; ">ous.close()<br />
</span></div>
<br />
Enjoy!<br />
<img src ="http://www.blogjava.net/sean/aggbug/355089.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2011-07-26 22:25 <a href="http://www.blogjava.net/sean/archive/2011/07/26/355089.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Pylons] Mako页面模板引擎</title><link>http://www.blogjava.net/sean/archive/2009/01/27/252614.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Tue, 27 Jan 2009 07:50:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2009/01/27/252614.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/252614.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2009/01/27/252614.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/252614.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/252614.html</trackback:ping><description><![CDATA[
		<br />Pylons是一个典型的MVC Web框架，在之前的几篇随笔中，我们一起了解了Pylons的安装、默认项目结构、Routes和controller("C")以及SQLAlchemy("M")，在这个系列的最后，我们一起来看看"V"。<br /><br />在我们的controller代码中，每个action在return的时候，可以选择：<br />1- 直接return字符串<br />2- 通过render()函数将输出交给页面模板引擎处理<br />3- redirect_to()重定向到其他URL<br /><br />直接return太简单，redirect_to也没有特别需要介绍的，重点看render()。如果你一直follow这个系列，那么在你的controllers/hello.py中，可以看到这样一行import：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> newapp.lib.base </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> BaseController, render</span></div><br />从lib.base引入了一个render函数，跟到lib/base代码里查看，我们会知道：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> pylons.templating </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> render_mako as render</span></div>其实我们用到的render()函数，是pylons.templating.render_mako的别名。<br /><br /><i>注: 这里假定你在paster create时选择了默认的mako，其他Pylons原生支持的页面模板引擎还有结构相对更层次化的Genshi和更接近Django实现的Jinja。<br /></i><br />render_mako()函数签名如下：<br />render_mako(template_name, extra_vars=None, cache_key=None, cache_type=None, cache_expire=None)<br /><br />最基本的用法是给出template文件名，然后通过extra_vars传入参数，Pylons默认查找页面模板文件是在项目的templates子目录，这个路径也可以在config/environment.py中修改。在Pylons中，被推荐的传参做法是使用tmpl_context，在生成controller的时候，已经自动import了tmpl_context并别名为c，这样，我们只需要在c上绑上我们需要传递给模板的数据，模板在解析时，也就能够通过c得到这些数据了。像这样：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">c.name </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> u</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Pylons n00b</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> render(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">hello.mako</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)</span></div><br />然后，在hello.mako中：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">h3</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">Hello </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">b</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">${c.name}</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">b</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">h3</span><span style="color: rgb(0, 0, 255);">&gt;</span></div><br />在模板代码中，有些Pylons系统变量/函数是可以直接访问的，包括：<br />tmpl_context (c) - 用于controller和template传递数据<br />config - 配置信息<br />app_globals (g) - 应用的全局变量<br />h - WebHelpers，包括h.form、h.link_to、h.url_for等等实用函数<br />request - 请求<br />response - 应答<br />session - 会话信息<br />translator、ungettext()、_()、N_() - 处理国际化<br /><br />除了基本的${}变量替代语法之外，类似JSP，Mako还支持注释、if/else/for控制逻辑、代码片段、return、标签等，具体的可以扫一眼官方说明：<br /><a target="_blank" title="http://www.makotemplates.org/docs/syntax.html" href="http://www.makotemplates.org/docs/syntax.html">http://www.makotemplates.org/docs/syntax.html</a><br />很精简，也非常容易理解，这里就不详细说明了。<br /><br />至此，我们已经了解了Pylons最核心的几个组件，足够我们搭建常规的Web应用了。其他值得大家继续挖掘的内容包括：国际化、表单验证(FormEncode)、用户验证和权限(AuthKit、repoze.who、repoze.what)、AJAX、Python 3.0、WSGI基础架构等。<br /><br />本文是该系列最后一篇，希望通过简单的介绍和学习，大家能够喜欢并顺利的上手Pylons，也希望越来越多的人关注这个优秀的Python Web应用框架。<br /><br /><img src ="http://www.blogjava.net/sean/aggbug/252614.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2009-01-27 15:50 <a href="http://www.blogjava.net/sean/archive/2009/01/27/252614.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Pylons] 在Pylons环境下使用SQLAlchemy</title><link>http://www.blogjava.net/sean/archive/2009/01/27/252612.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Tue, 27 Jan 2009 06:00:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2009/01/27/252612.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/252612.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2009/01/27/252612.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/252612.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/252612.html</trackback:ping><description><![CDATA[
		<br />在前面的4篇随笔中，我们简要的介绍了SQLAlchemy，不过SQLAlchemy如何被集成到Pylons应用中呢？<br /><br />首先我们看一下自动生成代码中的model子目录，其中有两个文件__init__.py和meta.py，其中meta.py定义了engine、Session和metadata三个公用变量，而__init__.py提供了一个核心的init_model(engine)方法，该方法分别将数据库engine和经过sessionmaker和scoped_session包装的Session对象植入到meta中，像这样：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">    sm </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> orm.sessionmaker(autoflush</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">True, autocommit</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">True, bind</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">engine)<br /><br />    meta.engine </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> engine<br />    meta.Session </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> orm.scoped_session(sm)</span></div><br />这样一来，整个背后的"magic"就还剩下最后一块"拼图"：谁来把engine初始化好并调用init_model方法呢？看看config/environment.py就清楚了：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(128, 0, 0);">Pylons environment configuration</span><span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> os<br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> mako.lookup </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> TemplateLookup<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> pylons.error </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> handle_mako_error<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> pylons </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> config<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> engine_from_config<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> newapp.lib.app_globals as app_globals<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> newapp.lib.helpers<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> newapp.config.routing </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> make_map<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> newapp.model </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> init_model<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">def</span><span style="color: rgb(0, 0, 0);"> load_environment(global_conf, app_conf):<br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(128, 0, 0);">Configure the Pylons environment via the ``pylons.config``<br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(128, 0, 0);">    object<br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(128, 0, 0);">    </span><span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> Pylons paths</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">    root </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> os.path.dirname(os.path.dirname(os.path.abspath(</span><span style="color: rgb(128, 0, 128);">__file__</span><span style="color: rgb(0, 0, 0);">)))<br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);">    paths </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> dict(root</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">root,<br /></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);">                 controllers</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">os.path.join(root, </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">controllers</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">),<br /></span><span style="color: rgb(0, 128, 128);">22</span> <span style="color: rgb(0, 0, 0);">                 static_files</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">os.path.join(root, </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">public</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">),<br /></span><span style="color: rgb(0, 128, 128);">23</span> <span style="color: rgb(0, 0, 0);">                 templates</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">[os.path.join(root, </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">templates</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)])<br /></span><span style="color: rgb(0, 128, 128);">24</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">25</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> Initialize config with the basic options</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">26</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">    config.init_app(global_conf, app_conf, package</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">newapp</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, paths</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">paths)<br /></span><span style="color: rgb(0, 128, 128);">27</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">28</span> <span style="color: rgb(0, 0, 0);">    config[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">routes.map</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> make_map()<br /></span><span style="color: rgb(0, 128, 128);">29</span> <span style="color: rgb(0, 0, 0);">    config[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">pylons.app_globals</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> app_globals.Globals()<br /></span><span style="color: rgb(0, 128, 128);">30</span> <span style="color: rgb(0, 0, 0);">    config[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">pylons.h</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newapp.lib.helpers<br /></span><span style="color: rgb(0, 128, 128);">31</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">32</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> Create the Mako TemplateLookup, with the default auto-escaping</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">33</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">    config[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">pylons.app_globals</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">].mako_lookup </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> TemplateLookup(<br /></span><span style="color: rgb(0, 128, 128);">34</span> <span style="color: rgb(0, 0, 0);">        directories</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">paths[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">templates</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">],<br /></span><span style="color: rgb(0, 128, 128);">35</span> <span style="color: rgb(0, 0, 0);">        error_handler</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">handle_mako_error,<br /></span><span style="color: rgb(0, 128, 128);">36</span> <span style="color: rgb(0, 0, 0);">        module_directory</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">os.path.join(app_conf[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">cache_dir</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">], </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">templates</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">),<br /></span><span style="color: rgb(0, 128, 128);">37</span> <span style="color: rgb(0, 0, 0);">        input_encoding</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">utf-8</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, output_encoding</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">utf-8</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">,<br /></span><span style="color: rgb(0, 128, 128);">38</span> <span style="color: rgb(0, 0, 0);">        imports</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">from webhelpers.html import escape</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">],<br /></span><span style="color: rgb(0, 128, 128);">39</span> <span style="color: rgb(0, 0, 0);">        default_filters</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">escape</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">])<br /></span><span style="color: rgb(0, 128, 128);">40</span> <span style="color: rgb(0, 0, 0);">    <br /></span><span style="color: rgb(0, 128, 128);">41</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> Setup SQLAlchemy database engine</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">42</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">    engine </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> engine_from_config(config, </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">sqlalchemy.</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">43</span> <span style="color: rgb(0, 0, 0);">    init_model(engine)<br /></span><span style="color: rgb(0, 128, 128);">44</span> <span style="color: rgb(0, 0, 0);">    <br /></span><span style="color: rgb(0, 128, 128);">45</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> CONFIGURATION OPTIONS HERE (note: all config options will override</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">46</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> any Pylons config options)<br /></span></div><br />注意第7行的import和第42、43行代码，是不是豁然开朗？Pylons在初始化运行环境时，从config中读取sqlalchemy相关的配置信息，然后通过这些配置信息创建数据库engine，并调用init_model()方法初始化SQLAlchemy功能的核心对象：metadata和Session。有了meta.Session，我们就可以方便的在代码中执行对model层/数据库的访问了。<br /><br /><img src ="http://www.blogjava.net/sean/aggbug/252612.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2009-01-27 14:00 <a href="http://www.blogjava.net/sean/archive/2009/01/27/252612.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Pylons] SQLAlchemy起步 - IV. Object Relational Mapper</title><link>http://www.blogjava.net/sean/archive/2009/01/27/252609.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Tue, 27 Jan 2009 04:52:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2009/01/27/252609.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/252609.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2009/01/27/252609.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/252609.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/252609.html</trackback:ping><description><![CDATA[
		<br />接着前面的例子说，我们定义了book_table和author_table，接下来：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Book(object):<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">def</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 128);">__init__</span><span style="color: rgb(0, 0, 0);">(self, title):<br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);">        self.title </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> title<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">def</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 128);">__repr__</span><span style="color: rgb(0, 0, 0);">(self):<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">&lt;Book('%s')&gt;</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">%</span><span style="color: rgb(0, 0, 0);"> self.title<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Author(object):<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">def</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 128);">__init__</span><span style="color: rgb(0, 0, 0);">(self, name):<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);">        self.name </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> name<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">def</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 128);">__repr__</span><span style="color: rgb(0, 0, 0);">(self):<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">&lt;Author('%s')&gt;</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">%</span><span style="color: rgb(0, 0, 0);"> self.name</span></div><br />这里我们定义两个类，继承自object，类似JavaBeans或者POJO，这里的__init__方法和__repr__方法不是必须的，只是为了创建对象和输出对象内容比较方便。然后就可以用SQLAlchemy的mapper和sessionmaker来建立映射关系并处理持久和查询等操作：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy.orm </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> mapper,sessionmaker<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);">mapper(Book, book_table)<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);">mapper(Author, author_table)<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">Session </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> sessionmaker(bind</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">engine)<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);">session </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Session()<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);">gia </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Book(u</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Groovy in Action</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);">ag </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Author(u</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Andrew Glover</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">session.add(gia)<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);">session.add(ag)<br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);">session.add_all([Book(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Hibernate in Action</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">), Author(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Gavin King</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)])<br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);">s_gia </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> session.query(Book).filter_by(title</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">u</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Groovy in Action</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">).first()<br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);">s_gia.title </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(128, 0, 0);">u'</span><span style="color: rgb(128, 0, 0);">Groovy in Action Updated</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">print</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">[DIRTY]</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, session.dirty<br /></span><span style="color: rgb(0, 128, 128);">19</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);">session.commit() # or session.rollback()<br /></span></div><br />如果你用过Hibernate，那么这些代码对你来说，理解起来应该没有任何难度。<br /><br />假如我告诉你，每次都要像这样先定义Table(schema)，再定义class，然后用mapper建立对照，是不是有点那啥？SQLAlchemy的开发者们也意识到这一点，所以从0.5开始，SQLAlchemy可以通过sqlalchemy.ext.declarative支持我们实现更紧凑的model/schema定义：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy.schema </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> Table, Column, ForeignKey, Sequence<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy.types </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy.orm </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> relation<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy.ext.declarative </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> declarative_base<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">Base </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> declarative_base()<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);">metadata </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Base.metadata<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);">bookauthor_table </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Table(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">bookauthor</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, metadata,<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);">    Column(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">book_id</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, Integer, ForeignKey(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">book.id</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">), nullable</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">False),<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">    Column(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">author_id</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, Integer, ForeignKey(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">author.id</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">), nullable</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">False),<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Book(Base):<br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(128, 0, 128);">__tablename__</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">book</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);">    id </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Column(Integer, Sequence(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">seq_pk</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">), primary_key</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">True)<br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 0, 0);">    title </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Column(Unicode(</span><span style="color: rgb(0, 0, 0);">255</span><span style="color: rgb(0, 0, 0);">), nullable</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">False)<br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 0, 0);">    authors </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> relation(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Author</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, secondary</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">bookauthor_table)<br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Author(Base):<br /></span><span style="color: rgb(0, 128, 128);">22</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(128, 0, 128);">__tablename__</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">author</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">23</span> <span style="color: rgb(0, 0, 0);">    id </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Column(Integer, Sequence(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">seq_pk</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">), primary_key</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">True)<br /></span><span style="color: rgb(0, 128, 128);">24</span> <span style="color: rgb(0, 0, 0);">    name </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Column(Unicode(</span><span style="color: rgb(0, 0, 0);">255</span><span style="color: rgb(0, 0, 0);">), nullable</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">False)<br /></span><span style="color: rgb(0, 128, 128);">25</span> <span style="color: rgb(0, 0, 0);">    books </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> relation(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Book</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, secondary</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">bookauthor_table)</span></div><br />这里我们用到了many-to-many关系，其他的常见用法还包括many-to-one、one-to-many、JOIN、子查询、EXISTS、Lazy/Eager Load、Cascade (all/delete/delete-orphan)等等，大家可以根据需要查阅官方文档。<br /><br /><img src ="http://www.blogjava.net/sean/aggbug/252609.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2009-01-27 12:52 <a href="http://www.blogjava.net/sean/archive/2009/01/27/252609.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Pylons] SQLAlchemy起步 - III. SQL Expression Language</title><link>http://www.blogjava.net/sean/archive/2009/01/26/252599.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Mon, 26 Jan 2009 15:40:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2009/01/26/252599.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/252599.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2009/01/26/252599.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/252599.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/252599.html</trackback:ping><description><![CDATA[
		<br />在介绍SQLAlchemy最核心最有价值的ORM部分之前，我们再简单过一遍SQLAlchemy提供的SQL Expression Language用法，就从最基本的CRUD来举例说明吧（接着上一篇的示例）：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> select,update,delete<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);">conn </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> engine.connect()<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);">book_ins </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> book_table.insert(values</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">dict(title</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">u</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Groovy in Action</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">))<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);">author_ins </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> author_table.insert(values</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">dict(name</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">u</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Andrew Glover</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">))<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">conn.execute(book_ins)<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);">conn.execute(author_ins)<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);">book </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> conn.execute(select([book_table], book_table.c.title.like(u</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Groovy%</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">))).fetchone()<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);">author </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> conn.execute(select([author_table])).fetchone()<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);">bookauthor_ins </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> bookauthor_table.insert(values</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">dict(book_id</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">book[0],author_id</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">author[0]))<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">conn.execute(bookauthor_ins)<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">conn.execute(update(book_table,book_table.c.title</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);">u</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Groovy in Action</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">), title</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">u</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Groovy in Action (中文版)</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);">conn.execute(delete(bookauthor_table))<br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);">conn.close()</span></div><br />简单说明一下代码逻辑：<br />首先从engine建立连接，然后做两个insert动作，分别insert一条book记录(title为'Groovy in Action')和一条author记录(name为'Andrew Glover')，这之后分别再做两次select，得到刚insert的这两条记录，其中book记录的select用到了过滤条件，相当于"WHERE book.title like 'Groovy%'"，然后构建一条新的insert语句，用于insert一条bookauthor关系记录，接下来，做一次update，将book.title为'Groovy in Action'的更新为'Groovy in Action (中文版)'，最后，在关闭连接之前，做一次delete，删除bookauthor中的记录。<br /><br />在指定WHERE条件时，.c是.columns的简写，所以book_table.c.title指代的就是book表的title列。更高级的用法是采用"&amp;"、"|"、"!"三个符号，分别表示AND、OR和NOT，加上必要的"("和")"实现复杂的条件定义。由于传递给select()的第一个参数是个list，所以你应该已经猜到了，我们也可以多张表做关联查询。<br /><br /><img src ="http://www.blogjava.net/sean/aggbug/252599.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2009-01-26 23:40 <a href="http://www.blogjava.net/sean/archive/2009/01/26/252599.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Pylons] SQLAlchemy起步 - II. MetaData和Types</title><link>http://www.blogjava.net/sean/archive/2009/01/26/252597.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Mon, 26 Jan 2009 14:14:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2009/01/26/252597.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/252597.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2009/01/26/252597.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/252597.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/252597.html</trackback:ping><description><![CDATA[
		<br />在sqlalchemy.schema和sqlalchemy.types这两个module中，包含了定义数据库schema所需要的所有类，如Table、Column、String、Text、Date、Time、Boolean等。还是来看一个例子：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy.engine </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> create_engine<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy.schema </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> MetaData, Table, Column, ForeignKey, Sequence<br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy.types </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);">engine </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> create_engine(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">postgres://test:test@localhost/test</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, echo</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">True)<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);">metadata </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> MetaData()<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);">metadata.bind </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> engine<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);">book_table </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Table(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">book</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, metadata,<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">    Column(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">id</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, Integer, Sequence(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">seq_pk</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">), primary_key</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">True),<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">    Column(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">title</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, Unicode(</span><span style="color: rgb(0, 0, 0);">255</span><span style="color: rgb(0, 0, 0);">), nullable</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">False),<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);">author_table </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Table(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">author</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, metadata,<br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);">    Column(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">id</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, Integer, Sequence(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">seq_pk</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">), primary_key</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">True),<br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 0, 0);">    Column(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, Unicode(</span><span style="color: rgb(0, 0, 0);">255</span><span style="color: rgb(0, 0, 0);">), nullable</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">False),<br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);">bookauthor_table </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Table(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">bookauthor</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, metadata,<br /></span><span style="color: rgb(0, 128, 128);"></span><span style="color: rgb(0, 128, 128);">21</span><span style="color: rgb(0, 0, 0);">    Column(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">book_id</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, Integer, ForeignKey(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">book.id</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">), nullable</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">False),<br /></span><span style="color: rgb(0, 128, 128);">22</span><span style="color: rgb(0, 0, 0);">    Column(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">author_id</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, Integer, ForeignKey(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">author.id</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">), nullable</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">False),<br /></span><span style="color: rgb(0, 128, 128);">23</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">24</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">25</span><span style="color: rgb(0, 0, 0);">metadata.create_all(checkfirst</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">True)</span></div><br />首先我们还是create_engine，然后新建一个MetaData对象，把engine绑上去，接下来，开始在metadata中定义表结构(metadata由Table构造函数传入)，我们这里定义了3张表，分别是book、author和bookauthor关系表(“多对多”)，其中新建一个Sequence对象，专门处理主键生成。最后我们通过执行metadata.create_all()创建数据库表，参数checkfirst=True表示如果数据库相关对象已经存在，则不重复执行创建。<br /><br />对于已经存在于数据库中的表，我们可以通过传入autoload=True参数到Table构造函数的方式来加载现有的表结构到metadata中，而不必挨个儿再写一遍Column清单。<br /><br />看到这儿，你也许觉得挺麻烦，不是么？Django和RoR都是可以直接定义数据model类，顺带就把schema也定义了，而不是像这样单独去写表结构的schema，显得很"底层"。确实，这样用SQLAlchemy并不是最优化的，SQLAlchemy本身并不会自动的帮你做很多事，但它基础打得很牢。如果你感兴趣，也可以先去看一下SQLAlchemy的扩展模块Elixir，通过Elixir，你可以像Ruby on Rails那样定义出实体和关系("Active Record")。<br /><br />在稍后的第4部分中，我们会去了解如何以声明方式来更紧凑的定义我们的model/schema(0.5新特性)。鉴于笔者倾向于更强的控制力，所以在这个系列中就不去介绍SQLAlchemy的其他扩展模块了，如Elixir、SQLSoup等，大家可以根据需要去找下官方文档。<br /><br /><img src ="http://www.blogjava.net/sean/aggbug/252597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2009-01-26 22:14 <a href="http://www.blogjava.net/sean/archive/2009/01/26/252597.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Pylons] SQLAlchemy起步 - I. Engine API</title><link>http://www.blogjava.net/sean/archive/2009/01/26/252592.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Mon, 26 Jan 2009 12:46:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2009/01/26/252592.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/252592.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2009/01/26/252592.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/252592.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/252592.html</trackback:ping><description><![CDATA[
		<br />ORM是个大话题，大到可能好几本书都说不完。SQLAlchemy，别看它刚出到0.5.2，已然是Python世界ORM的事实标准，受到众多开发者和无数框架的青睐。<br /><br />如果之前没有或很少接触SQLAlchemy，那么学习Pylons可能有相当一部分时间都会花在SQLAlchemy上。通常，人们选择Pylons或者TurboGears而不是Django，SQLAlchemy在这些决定的背后有着很重的分量。作为Pylons学习笔记的一部分，接下来我将分4篇随笔介绍SQLAlchemy，分别是Engine API、Schema Management (MetaData/Types)、SQL Expression Language和Object Relational Mapper。此文为第1篇，重点介绍Engine API。<br /><br />类似Java的JDBC，Python也有一个类似的数据库访问接口规范，那就是DB-API(目前是2.0)，不同的常见RDBMS都有符合DB-API标准的Python库，比如PostgreSQL有psycopg2，Oracle有cx_Oracle等。有了这个基础，SQLAlchemy也就得以方便的通过DB-API连接不同的数据库。<br /><br />以PostgreSQL为例，通过SQLAlchemy的Engine API访问数据库的代码可以这样来写：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> sqlalchemy.engine </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> create_engine<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);">engine </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> create_engine(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">postgres://user:pass@localhost/testdb</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);">connection </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> engine.connect()<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);">connection.execute(<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(128, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(128, 0, 0);">    CREATE TABLE book<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(128, 0, 0);">    (<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(128, 0, 0);">      id serial NOT NULL,<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(128, 0, 0);">     title character varying(30) NOT NULL,<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(128, 0, 0);">     CONSTRAINT pk_book PRIMARY KEY (id)<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(128, 0, 0);">    );<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(128, 0, 0);">   </span><span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);">connection.execute(<br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(128, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(128, 0, 0);">    INSERT INTO book (title) VALUES (%s);<br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(128, 0, 0);">    </span><span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(0, 0, 0);">,<br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">The Art of UNIX Programming</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);">rs </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> connection.execute(</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">SELECT title FROM book</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">22</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);"> row </span><span style="color: rgb(0, 0, 255);">in</span><span style="color: rgb(0, 0, 0);"> rs:<br /></span><span style="color: rgb(0, 128, 128);">23</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">print</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 0, 0);">Book Title: </span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, row[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">title</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">]<br /></span><span style="color: rgb(0, 128, 128);">24</span> <span style="color: rgb(0, 0, 0);">connection.close()<br /></span><span style="color: rgb(0, 128, 128);"></span><span style="color: rgb(0, 0, 0);"></span></div><br />基本步骤就是create_engine、connect、execute和close，没有很特别的地方，不过SQLAlchemy的Engine API，并不是简单的DBAPI调用，而是包装了其他内容，如数据库连接池，我们可以在create_engine的时候指定连接池参数和其他额外配置，类似这样：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">engine </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> create_engine(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">postgres://user:pass@localhost/testdb</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, pool_size</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">10, convert_unicode=True</span><span style="color: rgb(0, 0, 0);">)</span></div><br />类似Spring的JdbcTemplate，更多的时候，统一使用SQLAlchemy的Engine API而不是DB-API能给我们带来更大的灵活性，通常也更方便、更安全。<br /><br /><img src ="http://www.blogjava.net/sean/aggbug/252592.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2009-01-26 20:46 <a href="http://www.blogjava.net/sean/archive/2009/01/26/252592.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Pylons] Routes和controller，一个简单的例子</title><link>http://www.blogjava.net/sean/archive/2009/01/26/252583.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Mon, 26 Jan 2009 08:21:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2009/01/26/252583.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/252583.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2009/01/26/252583.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/252583.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/252583.html</trackback:ping><description><![CDATA[
		<br />在开始之前，说点提外话，随着对Pylons了解的深入，你可能时不时需要看看相关组件/软件包是否有更新出来，方法也不复杂，通过"easy_install -U [组件名]"即可，在学习或者是开发过程中，最好是保持环境相对较新，直到出现相对大的release或者即将进入产品部署阶段。<br /><br />继续介绍Pylons组件，先看个例子。首先用"paster controller hello"增加一个controller，路径中会增加出以下两个文件：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">controllers/hello.py<br />tests/functional/test_hello.py</span></div><br />分别对应新增的controller类HelloController和功能测试类TestHelloController，它们分别继承自WSGIController-&gt;BaseController和TestCase-&gt;TestController。<br /><br />我们主要看hello.py，默认内容如下：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> logging<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> pylons </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> request, response, session, tmpl_context as c<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> pylons.controllers.util </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> abort, redirect_to<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> newapp.lib.base </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> BaseController, render<br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);">from newapp import model</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);">log </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> logging.getLogger(</span><span style="color: rgb(128, 0, 128);">__name__</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> HelloController(BaseController):<br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">def</span><span style="color: rgb(0, 0, 0);"> index(self):<br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> Return a rendered template</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);">   return render('/template.mako')</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> or, Return a response</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">Hello World</span><span style="color: rgb(128, 0, 0);">'</span></div><br />如果你的服务器没有Ctrl-C停掉，那么这个时候你已经可以通过<br /><a target="_blank" title="http://127.0.0.1:5000/hello/index" href="http://127.0.0.1:5000/hello/index">http://127.0.0.1:5000/hello/index</a><br />看到该controller的处理结果了(Hello World)。<br /><br />简单改造一下17行：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> pylons </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> config<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">&lt;br/&gt;</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">.join(config.keys())</span></div><br />我们就可以在返回页面上显示出所有可以通过pylons.config访问到的参数列表。出了返回文本，也可以通过render()方法交给页面模板引擎生成页面，也可以通过redirect_to()跳转到其他URL。<br /><br />Pylons是如何找到该请求应该由HelloController的index方法来处理的呢？这背后发生了什么？答案就是Routes。<br /><br />Routes的作者是Ben Bangert，是Pylons框架三个主要作者/维护者之一，早期的版本主要是仿照Ruby on Rails的routes.rb开发的，有RoR经验的朋友可能一眼就能发现它们之间的相似之处。目前Routes的最新版是1.10.2。<br /><br />Pylons应用中，routing的配置在config/routing.py，默认生成的内容如下：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(128, 0, 0);">Routes configuration<br /></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(128, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(128, 0, 0);">The more specific and detailed routes should be defined first so they<br /></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(128, 0, 0);">may take precedent over the more generic routes. For more information<br /></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(128, 0, 0);">refer to the routes manual at http://routes.groovie.org/docs/<br /></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(128, 0, 0);"></span><span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> pylons </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> config<br /></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> routes </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> Mapper<br /></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">def</span><span style="color: rgb(0, 0, 0);"> make_map():<br /></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(128, 0, 0);">Create, configure and return the routes Mapper</span><span style="color: rgb(128, 0, 0);">"""</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">    map </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Mapper(directory</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">config[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">pylons.paths</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">][</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">controllers</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">],<br /></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);">                 always_scan</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">config[</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">debug</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">])<br /></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);">    map.minimization </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> False<br /></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);">    <br /></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> The ErrorController route (handles 404/500 error pages); it should</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> likely stay at the top, ensuring it can always be resolved</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">    map.connect(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">/error/{action}</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, controller</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">error</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 0, 0);">    map.connect(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">/error/{action}/{id}</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">, controller</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">error</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);"> CUSTOM ROUTES HERE</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 128, 128);">22</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">23</span> <span style="color: rgb(0, 0, 0);">    map.connect(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">/{controller}/{action}</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">24</span> <span style="color: rgb(0, 0, 0);">    map.connect(</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">/{controller}/{action}/{id}</span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 128, 128);">25</span> <span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 128, 128);">26</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> map</span></div><br />在这个配置中，对我们刚才的实例起到决定性作用的是第23行，我们的输入URL为"http://127.0.0.1:5000/hello/index"，其中"/hello/index"通过"/{controller}/{action}"这个表达式match出controller为hello而action为index的解析结果，从而在controllers目录找到hello.py，和其中HelloController的index方法，进行调用。<br /><br />map.connect()在上面代码中体现出两种用法：<br />map.connect('pattern', key=value) - 指定默认的controller、action、id等<br />map.connect('pattern') - 直接指定pattern<br /><br />pattern字符串允许通配符，通常在最后一个元素上，比如'/{controller}/{action}/{*url}'，将后面的整个URL片段交给前面指定的controller/action处理。除此以外，map.connect()还支持<br /><br />1- "路径别名"，如：<br />map.connect('name', 'pattern', [_static=True])<br />如果_static设为"True"，表示为"静态命名路径"。<br />2- 额外的匹配条件，如：<br />map.connect('/{controller}/{action}/{id}', requirements={'year': '\d+',})<br />map.connect('/{controller}/{action}/{id}', conditions=dict(method=['GET','POST']))<br /><br />所有的route优先级为从上到下。Routes除了提供解析进来的URL的逻辑，在我们的controller和template代码中，我们还可以方便的通过WebHelpers的url_for()方法计算相应的URL。<br /><br />Routes 1.x中的有一些仿routes.rb功能将会在2.0中被去掉，包括Route Minimization、Route Memory、Implicit Defaults等。如果有兴趣的话，可以参考一下官方文档，这里就不一一介绍了。为什么要去掉？当然主要的动机还是减少歧义，避免一些不必要的混淆。至于深层次的原因么，可以参考Tim Peters《The Zen of Python》中的一句经典的Python哲学：Explicit is better than implicit。什么？没有听说过？打开python命令行，输入"import this"后回车，慢慢体会其中的道理吧。:)<br /><br /><br /><img src ="http://www.blogjava.net/sean/aggbug/252583.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2009-01-26 16:21 <a href="http://www.blogjava.net/sean/archive/2009/01/26/252583.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Pylons] 默认项目结构</title><link>http://www.blogjava.net/sean/archive/2009/01/26/252579.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Mon, 26 Jan 2009 04:33:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2009/01/26/252579.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/252579.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2009/01/26/252579.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/252579.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/252579.html</trackback:ping><description><![CDATA[
		<br />大家新年好！<br /><br />在<a target="_blank" title="http://www.blogjava.net/sean/archive/2009/01/25/252561.html" href="/sean/archive/2009/01/25/252561.html">前一篇随笔</a>中，大家了解了什么是Pylons，有哪些特点，今天笔者继续给介绍默认生成的项目结构。<br /><br />通过Paste创建新的Pylons应用很简单，就是一句"paster create -t pylons [应用名]"命令，其中"-t pylons"或者全称"--template=pylons"，用以告诉Paste我们新建的项目，将是一个Pylons应用，或者说，从一个预定义好的Pylons默认项目模板生成。如果你愿意，你也可以自己来制作新的模板以符合需要。"paster create --list-templates"可以查看当前可用的模板。<br /><br />假定我们新建的Pylons项目名称为NewApp，那么执行"paster create -t pylons NewApp"后，我们将得到一个新的NewApp目录，其中包含一个docs目录(文档)、一个newapp目录(代码)、一个NewApp.egg-info目录(元数据)和一些顶级配置文件。<br /><br />在开发过程中，我们经常会用到的是代码目录(这里是newapp)和位于项目根目录下的development.ini和test.ini文件了。注意这里newapp的大小写，Pylons在生成项目的时候，不论你指定的项目名称大小写是怎样，这里会自动.lower()转小写，只有项目顶级路径和egg信息会保留原始大小写，笔者认为这更加符合Web应用的nature。<br /><br />代码目录下包括config、controllers、lib、model、public、templates和tests子目录，分别用于存放配置(如环境、中间件、路径查找逻辑)、控制器(处理请求)、全局辅助代码(全局变量、helpers等)、模型(后台数据访问)、静态页面/媒体文件、页面模板和测试代码。<br /><br />最后说说ini文件：默认生成的development.ini和test.ini顾名思义分别对应开发和测试需要的基本配置，我们可以通过修改相应的参数配置来指定具体设定，如服务器IP和端口、数据库连接、日志等。看到这里你也许会问，那么产品环境呢？答案是默认没有生成，你可以从development.ini修改成需要的产品环境配置，也可以通过paster make-config newapp production.ini生成一个默认的产品环境典型配置。<br /><br />以development.ini为例，Pylons的ini文件主要包括4个部分的内容：<br /><br />1- 全局默认参数，如<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">DEFAULT</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />debug </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> true<br /># Uncomment and replace with the address which should receive any error reports<br />#email_to </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> you@yourdomain.com<br />smtp_server </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> localhost<br />error_email_from </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> paste@localhost</span></div><br /><br /><br />2- 服务器配置，如<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">server:main</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />use </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> egg:Paste#http<br />host </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">127.0.0.1</span><span style="color: rgb(0, 0, 0);"><br />port </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">5000</span></div><br /><br /><br />3- 应用程序配置，如<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">app:main</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />use </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> egg:NewApp<br />full_stack </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> true<br /><br />cache_dir </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> %(here)s/data<br />beaker.session.key </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newapp<br />beaker.session.secret </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> somesecret<br /><br /># If you'd like to fine-tune the individual locations of the cache data dirs<br /># for the Cache data</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"> or the Session saves</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"> un-comment the desired settings<br /># here:<br />#beaker.cache.data_dir </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> %(here)s/data/cache<br />#beaker.session.data_dir </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> %(here)s/data/sessions<br /><br /># SQLAlchemy database URL<br />sqlalchemy.url </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> sqlite:///%(here)s/development.db<br /><br /># WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*<br /># Debug mode will enable the interactive debugging tool</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"> allowing ANYONE to<br /># execute malicious code after an exception is raised.<br />#set debug </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> false<br /></span></div>简单说明一下，这里的full_stack设置为true表示打开交互式调试和错误报告等功能，"%(here)s"会被替换成项目所在路径，类似相对路径url中的"."转绝对路径，而beaker.*为配置会话相关的设定，如缓存、cookie基本内容等。对于产品环境来说，比较重要的一个配置是"set debug=false"，否则一旦出现异常，交互式调试将使得攻击者能够执行系统命令。<br /><br />4- 日志，如<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">loggers</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />keys </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> root</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"> routes</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"> newapp</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"> sqlalchemy<br /><br /></span><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">handlers</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />keys </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> console<br /><br /></span><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">formatters</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />keys </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> generic<br /><br /></span><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">logger_root</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />level </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> INFO<br />handlers </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> console<br /><br /></span><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">logger_routes</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />level </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> INFO<br />handlers </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"><br />qualname </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> routes.middleware<br /># </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">level = DEBUG</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> logs the route matched and routing variables.<br /><br /></span><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">logger_newapp</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />level </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> DEBUG<br />handlers </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"><br />qualname </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newapp<br /><br /></span><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">logger_sqlalchemy</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />level </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> INFO<br />handlers </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"><br />qualname </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> sqlalchemy.engine<br /># </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">level = INFO</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> logs SQL queries.<br /># </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">level = DEBUG</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> logs SQL queries and results.<br /># </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">level = WARN</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> logs neither.  (Recommended for production systems.)<br /><br /></span><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">handler_console</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />class </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> StreamHandler<br />args </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> (sys.stderr</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">)<br />level </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> NOTSET<br />formatter </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> generic<br /><br /></span><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">formatter_generic</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"><br />format </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> %(asctime)s</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">%(msecs)03d %(levelname)-</span><span style="color: rgb(0, 0, 0);">5</span><span style="color: rgb(0, 0, 0);">.5s </span><span style="color: rgb(128, 0, 0); font-weight: bold;">[</span><span style="color: rgb(128, 0, 0);">%(name)s</span><span style="color: rgb(128, 0, 0); font-weight: bold;">]</span><span style="color: rgb(0, 0, 0);"> %(message)s<br />datefmt </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> %H:%M:%S</span></div><br />OK，这一篇就先讲到这儿，下一篇将介绍Routes和controller。<br /><br /><br /><img src ="http://www.blogjava.net/sean/aggbug/252579.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2009-01-26 12:33 <a href="http://www.blogjava.net/sean/archive/2009/01/26/252579.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[Pylons] 简介+安装指南</title><link>http://www.blogjava.net/sean/archive/2009/01/25/252561.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Sun, 25 Jan 2009 12:05:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2009/01/25/252561.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/252561.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2009/01/25/252561.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/252561.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/252561.html</trackback:ping><description><![CDATA[
		<br />Pylons是一个Python语言的Web应用程序框架，如果你简单了解过Ruby on Rails和Django，你大概会问，Pylons有什么不一样呢？Pylons最大的特点是模块化，将处理Web应用环境下不同领域、不同问题的软件包集成在一起，形成一个整体，在提供一揽子解决方案的同时，不阻碍你选择别的替代组件。另外，Pylons是目前对WSGI标准支持最好的框架之一，未来的TurboGears 2.0也会基于Pylons构建。<br /><br />Pylons从Ruby on Rails借鉴了不少东西，比如Routes，比如WebHelpers，从表面看更像是Python版的RoR，不过底下的架构应该说更加轻量和灵活，因为你可以灵活选择自己熟悉或者更贴和具体应用实际的组件，从ORM到页面模板，Pylons只是推荐一些大家普遍比较认可的选项，但并不强制你使用它们。<br /><br />说完和Ruby on Rails的异同，当然也要回过头来说说同样是Python编写的Django。如果你只是想迅速的构建一个可以支撑大量访问的Web应用，Django是个不错的选择，但和RoR一样，你在很大程度上被限制在一定的pattern中：如果你按照Django的思路去实现你的应用，你会很happy；但一旦你觉得某个组件你不喜欢、不符合某个实际要求，想要来点定制，你就会觉得有些伸不开拳脚，或者工程浩大。目前感觉Django比较不爽的地方有：页面模板较弱，表现力有些不足，也有人说够用了；ORM目前是自己的一套，暂时没有成熟的SQLAlchemy支持，需要第三方包或者自己做；从架构上，Django对MVC的解读是MTV(Model-Template-View)，大家都叫作controller的东东，在Django的世界里是view，以至于每次和别人解释，都要多费一番口舌。<br /><br />Pylons目前版本是0.9.7(rc4)，主要用到的第三方/独立组件有Paste、Routes、Beaker、Mako、FormEncode、WebHelpers和SQLAlchemy。安装方法如下：<br /><br />首先你必须有Python(2.3+)，然后你可以选择直接easy_install Pylons或者新建一个Virtual Environment，和系统中的Python环境隔离开，依赖的包可以独立升级。这里我们按照后一种方式，如果你是第一次使用Pylons，建议你也在独立Python virtualenv中安装。<br /><br />1- easy_install virtualenv (这将安装Python虚拟环境工具)<br />2- python virtualenv.py ENV (创建新的虚拟环境。这里的ENV是你新建虚拟环境的路径，如"mydevenv")<br />3- source ENV/bin/activate (激活虚拟环境。如果是Windows的话，这里需要执行ENV\bin\activate.bat)<br />4- easy_install Pylons (这里使用的是虚拟环境的easy_install安装)<br /><br />如果你觉得上面的步骤麻烦，Pylons开发团队提供了一个脚本来处理安装过程，下载后用Python执行即可：<br /><a target="_blank" title="http://www.pylonshq.com/download/0.9.7/go-pylons.py" href="http://www.pylonshq.com/download/0.9.7/go-pylons.py">http://www.pylonshq.com/download/0.9.7/go-pylons.py</a><br /><br />如果需要SQLAlchemy，则再执行一下<br />easy_install SQLAlchemy<br /><br />安装成功后，通过<br />paster create -t pylons [应用名]<br />即可新建Web应用主框架，然后cd到应用下，通过<br />paster serve --reload development.ini<br />启动Web服务，默认地址在<br /><a target="_blank" title="http://127.0.0.1:5000/" href="http://127.0.0.1:5000/">http://127.0.0.1:5000/</a><br /><br />更详细的信息，可参考Pylons项目主页：<br /><a target="_blank" title="http://pylonshq.com/" href="http://pylonshq.com/">http://pylonshq.com/</a><br /><br />随着使用的深入，笔者还会陆续对Pylons和其他相关组件进行进一步的介绍。祝各位农历新年快乐！<br /><br /><br /><img src ="http://www.blogjava.net/sean/aggbug/252561.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2009-01-25 20:05 <a href="http://www.blogjava.net/sean/archive/2009/01/25/252561.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[备忘] 如何确定当前Python环境的site-packages目录</title><link>http://www.blogjava.net/sean/archive/2009/01/23/252479.html</link><dc:creator>laogao</dc:creator><author>laogao</author><pubDate>Fri, 23 Jan 2009 11:25:00 GMT</pubDate><guid>http://www.blogjava.net/sean/archive/2009/01/23/252479.html</guid><wfw:comment>http://www.blogjava.net/sean/comments/252479.html</wfw:comment><comments>http://www.blogjava.net/sean/archive/2009/01/23/252479.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sean/comments/commentRss/252479.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sean/services/trackbacks/252479.html</trackback:ping><description><![CDATA[
		<br />有时我们需要动态的确定当前采用的Python运行时环境对应的site-packages目录，在Python代码中，可以这样做：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">from</span><span style="color: rgb(0, 0, 0);"> distutils.sysconfig </span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);"> get_python_lib<br /></span><span style="color: rgb(0, 0, 255);">print</span><span style="color: rgb(0, 0, 0);"> get_python_lib()</span></div><br />备忘。<br /><br /><img src ="http://www.blogjava.net/sean/aggbug/252479.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sean/" target="_blank">laogao</a> 2009-01-23 19:25 <a href="http://www.blogjava.net/sean/archive/2009/01/23/252479.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>