<?xml version="1.0" encoding="gb2312"?>
<rss version="2.0">
<channel>
<title><![CDATA[limodou的学习生活]]></title>
        <image>
        <title>http://hi.baidu.com</title>
        <link>http://hi.baidu.com</link>
        <url>http://img.baidu.com/img/logo-hi.gif</url>
        </image>
<description><![CDATA[Python, open source, ...]]></description>
<link>http://hi.baidu.com/limodou</link>
<language>zh-cn</language>
<generator>www.baidu.com</generator>
<ttl>5</ttl>


<item>
        <title><![CDATA[UliPad 4.0发布]]></title>
        <link><![CDATA[http://hi.baidu.com/limodou/blog/item/83e7f31f4250a269f724e462.html]]></link>
        <description><![CDATA[
		
		<p>本来是懒得发布，因为最新更新也不是很多，不过从3.9发布到现在竟然也有1年多了，3.9发布还是在08年4月份，想不到时间过得真快啊。</p>
<span class="Apple-style-span" style="word-spacing: 0px; font: medium  YaHei Consolas Hybrid ; text-transform: none; color: rgb(0,0,0); text-indent: 0px; white-space: normal; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2; webkit-border-horizontal-spacing: 0px; webkit-border-vertical-spacing: 0px; webkit-text-decorations-in-effect: none; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px"><span class="Apple-style-span" style="font-size: 14px;  border-collapse: collapse">
<h1><a style="color: rgb(119,153,187)" name="12523f9f988a0757_links">Links</a></h1>
<ul>
    <li style="margin-left: 15px">Project:<span class="Apple-converted-space"> </span><a style="color: rgb(119,153,187)" href="http://code.google.com/p/ulipad" target="_blank">http://code.google.com/p/<wbr></wbr>ulipad</a></li>
    <li style="margin-left: 15px">source version:<span class="Apple-converted-space"> </span><a style="color: rgb(119,153,187)" href="http://ulipad.googlecode.com/files/ulipad.4.0.zip" target="_blank">http://ulipad.googlecode.com/<wbr></wbr>files/ulipad.4.0.zip</a></li>
    <li style="margin-left: 15px">windows exe version:<span class="Apple-converted-space"> </span><a style="color: rgb(119,153,187)" href="http://ulipad.googlecode.com/files/ulipad.4.0.py25.exe" target="_blank">http://ulipad.googlecode.com/<wbr></wbr>files/ulipad.4.0.py25.exe</a></li>
    <li style="margin-left: 15px">maillist:<span class="Apple-converted-space"> </span><a style="color: rgb(119,153,187)" href="http://groups.google.com/group/ulipad" target="_blank">http://groups.google.com/<wbr></wbr>group/ulipad</a></li>
    <li style="margin-left: 15px">ulipad snippets site:<span class="Apple-converted-space"> </span><a style="color: rgb(119,153,187)" href="http://ulipad.appspot.com/" target="_blank">http://ulipad.appspot.com</a><span class="Apple-converted-space"> </span>(hosted by GAE)</li>
</ul>
</span></span> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/limodou/blog/category/Ulipad">Ulipad</a>&nbsp;<a href="http://hi.baidu.com/limodou/blog/item/83e7f31f4250a269f724e462.html#comment">查看评论</a>]]></description>
        <pubDate>2009-11-24  10:27</pubDate>
        <category><![CDATA[Ulipad]]></category>
        <author><![CDATA[limodou]]></author>
		<guid>http://hi.baidu.com/limodou/blog/item/83e7f31f4250a269f724e462.html</guid>
</item>

<item>
        <title><![CDATA[Uliweb在stdyun的部署说明]]></title>
        <link><![CDATA[http://hi.baidu.com/limodou/blog/item/1e7ca044e927f088b2b7dcdb.html]]></link>
        <description><![CDATA[
		
		<p><a target="_blank" href="http://stdyun.com">stdyun</a>是张沈鹏同学做的主机系统，在开始我申请了他提供了免费试用帐号，主要是想试一下Uliweb的部署。在使用过程中由于开始不太熟悉，获得了张教主的帮助，成功将uliwebproject部署成功，目前可以通过 uliweb.com.cn来访问（由于是试用期，因此可能随时关闭）。这个主机系统创建不久，目前已经开始可以租用，速度真是很快，提供ssh，mysql。下面是我将Uliweb的部署写出来，为Uliweb感兴趣的人提供一个部署的实例。所有尝试以svn中的最新版本为准。</p>
<p>在stdyun上部署Uliweb还算方便。</p>
<p><font size="4"><strong>准备工作</strong></font></p>
<p>因为stdyun不提供缺省的二级域名，因此需要用户自行去注册一个域名并进行绑定。具体如何申请和绑定<br>
张教主在我的问题中给了很好的回答，可以参考：</p>
<p><a href="http://groups.google.com/group/python-cn/browse_thread/thread/3b00351b97b6690a/bb28c5ec135d1b7b">http://groups.google.com/group/python-cn/browse_thread/thread/3b00351b97b6690a/bb28c5ec135d1b7b</a></p>
<p><font size="4"><strong>stdyun环境介绍</strong></font></p>
<p>一旦你申请帐号成功，stdyun会发送给你有关ssh，mysql的信息，因此你可以使用putty进行登录。具体登录过程不再说明。</p>
<p>stdyun已经安装好了一些环境，比如virtualenv，setuptools, easy_install。并且它所提供的python是最新的2.6.4。你可以认为在你的目录下已经有了基础的python环境了。</p>
<p>virtualenv是一个很方便在一个受限环境下创建一个完整的python的工具，由于stdyun已经安装好了因此你不再需要安装。并且它已经被激活，所以激活这步也不用执行了。直接使用就好了。</p>
<p>bin 目录是存放一些命令，如python，virtualenv的命令行工作，easy_install等。如果你在virtualenv下安装python模块，那么当存在scripts需要安装时，会安装到这个目录下。</p>
<p>lib 用来放置python下的库。安装的python库源文件就放在这个目录下。</p>
<p><font size="4"><strong>Uliweb软件安装</strong></font></p>
<p>因为你已经有了一个完全由你控制的python 2.6的环境（Uliweb可以运行在2.6下），因此你可以按照Uliweb的安装说明进行操作，完全没有问题。这里我列出通过svn来安装的步骤，这样便于与Uliweb的svn保持同步。</p>
<p>为了方便，你可以在$HOME目录下创建一个src的目录，然后进入这个目录，再在这个目录下通过svn获得Uliweb的代码，如：</p>
<p>
<table class="FCK__ShowTableBorders" border="0">
    <tbody>
        <tr>
            <td valign="top" align="right">
            <pre><font face="Lucida,Courier New" color="#000000">  1 
  2 
  3 
  4 
  5 </font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#000000">mkdir</font> <font color="#000000">src</font>
<font color="#000000">cd</font> <font color="#000000">src</font>
<font color="#000000">svn</font> <font color="#000000">checkout</font> <font color="#000000">http</font><font color="#0000c0">:</font><font color="#0000c0">//</font><font color="#000000">uliweb</font><font color="#0000c0">.</font><font color="#000000">googlecode</font><font color="#0000c0">.</font><font color="#000000">com</font><font color="#0000c0">/</font><font color="#000000">svn</font><font color="#0000c0">/</font><font color="#000000">trunk</font><font color="#0000c0">/</font> <font color="#000000">uliweb</font>
<font color="#000000">cd</font> <font color="#000000">uliweb</font>
<font color="#000000">python</font> <font color="#000000">setup</font><font color="#0000c0">.</font><font color="#000000">py</font> <font color="#000000">develop</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>这样就安装好Uliweb了。</p>
<p><font size="4"><strong>创建Hello</strong></font></p>
<p>让我们回到$HOME目录下</p>
<p>
<table class="FCK__ShowTableBorders" border="0">
    <tbody>
        <tr>
            <td valign="top" align="right">
            <pre><font face="Lucida,Courier New" color="#000000">  1 
  2 
  3 
</font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#000000">uliweb</font> <font color="#000000">makeproject</font> <font color="#000000">hello</font>
<font color="#000000">cd</font> <font color="#000000">hello</font>
<font color="#000000">uliweb</font> <font color="#000000">makeapp</font> <font color="#000000">Hello</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
这时我们的Demo项目就建好了。</p>
<p><font size="4"><strong>部署</strong></font></p>
<p>stdyun是使用fastcgi模式。而Uliweb已经提供了这么一个文件，就在hello目录下。检查一下runcgi.fcgi它的执行权限是否是x。如果不是请修改：</p>
<p>
<table class="FCK__ShowTableBorders" border="0">
    <tbody>
        <tr>
            <td valign="top" align="right">
            <pre><font face="Lucida,Courier New" color="#000000">  1 
</font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#000000">chmod</font> <font color="#0000c0">+</font><font color="#000000">x</font> <font color="#000000">runcgi</font><font color="#0000c0">.</font><font color="#000000">fcgi</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
不过这步一般不需要做，在最新的Uliweb代码中，通过svn检出的话应该已经是可执行权限了。</p>
<p>然后要修改一下runcfi.fcgi，主要是第一行改为：</p>
<p>
<table class="FCK__ShowTableBorders" border="0">
    <tbody>
        <tr>
            <td valign="top" align="right">
            <pre><font face="Lucida,Courier New" color="#000000"> 1 
</font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#008000">#!/home/vhost/s63/bin/python</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
这里s63是我的用户编号，你要改成你自已的编号。</p>
<p>修改完毕，然后就需要在stdyun的控制面板添加url与handler的对应关系。</p>
<p><font size="4"><strong>绑定</strong></font></p>
<p>进入： <a href="http://stdyun.com/vhost/my">http://stdyun.com/vhost/my</a><br>
在下面的绑定域名处添加你申请的域名，如demo.uliweb.com.cn，然后点击绑定域名。</p>
<p><span><img class="blogimg" border="0" small="0" src="http://hiphotos.baidu.com/limodou/pic/item/2fbfa9d3941b8b1a970a16b0.jpg"><br>
</span>输入后进入目录绑定界面。我们想通过 demo.uliweb.com.cn来访问hello项目。配置如下：</p>
<p><span><img class="blogimg" border="0" small="0" src="http://hiphotos.baidu.com/limodou/pic/item/a68fb838a15985ecd56225bd.jpg"><br>
</span>输入后点添加即可。</p>
<p>然后过一会再访问你的域名。如 <a target="_blank" href="http://demo.uliweb.com.cn/">http://demo.uliweb.com.cn</a> 你会看到一个Hello, Uliweb的信息显示出来了。</p>
<p> </p> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/limodou/blog/category/Uliweb">Uliweb</a>&nbsp;<a href="http://hi.baidu.com/limodou/blog/item/1e7ca044e927f088b2b7dcdb.html#comment">查看评论</a>]]></description>
        <pubDate>2009-11-12  21:33</pubDate>
        <category><![CDATA[Uliweb]]></category>
        <author><![CDATA[limodou]]></author>
		<guid>http://hi.baidu.com/limodou/blog/item/1e7ca044e927f088b2b7dcdb.html</guid>
</item>

<item>
        <title><![CDATA[uliweb.com.cn]]></title>
        <link><![CDATA[http://hi.baidu.com/limodou/blog/item/a68fb838e98dddc8d46225ed.html]]></link>
        <description><![CDATA[
		
		<span class="Apple-style-span" style="word-spacing: 0px; font: medium YaHei Consolas Hybrid; text-transform: none; color: rgb(0,0,0); text-indent: 0px; white-space: normal; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2; webkit-border-horizontal-spacing: 0px; webkit-border-vertical-spacing: 0px; webkit-text-decorations-in-effect: none; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px">
<div style="font-weight: normal; font-size: 14px; line-height: normal; font-style: normal; background-color: rgb(255,255,255); background-origin: initial; background-clip: initial">
<p><span style="border-collapse: collapse" mce_style="border-collapse: collapse;">感谢张教主的帮助，不过现在还有一点点小问题，因为有些包还没装上。不过首页已经可以访问了。uliweb已经在张教主的stdyun上部署成功了。几点事项：<span class="Apple-converted-space"> </span><br>
<br>
域名（我去的9host.cn申请的，.<span class="Apple-converted-space"> </span>com.cn<span class="Apple-converted-space"> </span>只要3块钱，续费要50元）<span class="Apple-converted-space"> </span><br>
有了域名要设置对应的IP（IP为：119.88.56.193），具体见张教主的说明(<span class="Apple-style-span" style="font-size: small; border-collapse: separate">同时要注意修改9host的DNS时要使用IE浏览器。<span> <span class="Apple-style-span" style="font-size: 14px; border-collapse: collapse">) &nbsp;&nbsp;</span></span></span></span></p>
<p><span style="border-collapse: collapse" mce_style="border-collapse: collapse;"><a style="color: rgb(119,153,187)" target="_blank" mce_style="color: #7799bb;" mce_href="http://groups.google.com/group/python-cn/browse_thread/thread/3b00351b97b6690a" href="http://groups.google.com/group/python-cn/browse_thread/thread/3b00351b97b6690a#">http://groups.google.com/group/python-cn/browse_thread/thread/3b00351b97b6690a#<span class="Apple-converted-space"> </span></a><br>
然后runcgi.py需要将后缀改为.fcgi。 不过这个我要再更新一下uliweb。<span class="Apple-converted-space"> </span><br>
<br>
回头我会写一个更详细的uliweb在stdyun上的部署说明。</span></p>
<p>声明，<font color="#ff0000">因为我使用的是免费试用，因此可能用的时间不会太长</font>。</p>
</div>
</span> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/limodou/blog/category/Uliweb">Uliweb</a>&nbsp;<a href="http://hi.baidu.com/limodou/blog/item/a68fb838e98dddc8d46225ed.html#comment">查看评论</a>]]></description>
        <pubDate>2009-11-05  12:52</pubDate>
        <category><![CDATA[Uliweb]]></category>
        <author><![CDATA[limodou]]></author>
		<guid>http://hi.baidu.com/limodou/blog/item/a68fb838e98dddc8d46225ed.html</guid>
</item>

<item>
        <title><![CDATA[Uliweb之Cache]]></title>
        <link><![CDATA[http://hi.baidu.com/limodou/blog/item/294d09fa7030b69d59ee90dd.html]]></link>
        <description><![CDATA[
		
		<span class="Apple-style-span" style="background-color: transparent; border-collapse: separate; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;">
<div style="font-size: 14px; line-height: normal; font-style: normal; font-weight: normal; background-color: rgb(255, 255, 255);">
<p>在经过对beaker中的session替换之后，我终于又把cache给替换掉了。完全是自个儿重写。一方面它可以象一个dict一样工作，同时可以通过put, get来调用。使用这两个函数的好处就是可以有更多的参数。目前这个类在uliweb/lib/weto/cache.py中。</p>
<p>创建cache</p>
<p>import weto.cache</p>
<p>cache = weto.cache.Cache()</p>
<p>这样可以创建一个cache。因为没有指定Cache类的初始化参数，因此会自动以file格式创建cache。如果需要指定其它的格式和参数，可以设置：</p>
<p>storage_type, options, expiry_time</p>
<p>这三个参数。storage是类型，目前只支持'file', 'dbm', 'database'，分别对应三种不同的存储类型。</p>
<p>options则根据不同的类型有所区别，比如'file'类型需要传入'data_dir'，用以指定cache保存的路径。而'database'则需要指明要使用的表名和数据库连接的一些信息。</p>
<p>expiry_time是指定缺省的超时时间。这是当你在put时没有指定超时时间时使用的，在调用put时可以单独设定。</p>
<p>cache.get(key)</p>
<p>这样的调用，如果key不存在，或超时则会引发一个异常抛出CacheKeyException异常。</p>
<p>如果不想引发异常，则可以：</p>
<p>cache.get(key, default)</p>
<p>其中default不能为None，这样当key不存在，则不会引发异常，返回default值。如果为None，则同get(key)的效果。</p>
<p>cache.put(key, value, expire=None)</p>
<p>这样可以设置一个cache。如果expire没有传入则使用缺省的超时时间。时间以秒为单位。</p>
<p>同时为了方便函数的封装，还提供了</p>
<p>cache.cache(key=None, expire=None)</p>
<p>这个decorator。例如：</p>
<p>@cache.cache(expire=15)<span class="Apple-converted-space">&#160;</span><br>
def f(*args, **kwargs):</p>
<p>或</p>
<p>@cache.cache(key, expire=15)<span class="Apple-converted-space">&#160;</span><br>
def f(*args, **kwargs):</p>
<p>这两种都是可以的，区别在于前一个没有key参数，那它将根据函数名和参数来生成一个key，而后面则是由用户主动指定了一个key。</p>
<p>在进行上进的改造之后，原来的beaker就删除了，这样uliweb中不再使用beaker了。同时对原uliweb.contrib.cache进行了修改，去掉了middle_cache.py，而采用让用户自行调用的机制。同时为了同app的配置功能相结合和方便用户使用，在uliweb/utils/cache.py中编写了一个get_cache()的函数，同时对Cache类的增加了page方法。</p>
<p>get_cache()可以自动从settings中找到相应的配置。目前主通过两个secion来控制的：</p>
<p>[CACHE]和[CACHE_STORAGE]，前者用来控制cache的类型和超时时间。后者是用来针对每一种类型来设置与存储相关的配置信息。在调用get_cache()时，你还可以传入一些参数，它的原型是：</p>
<p>def get_cache(cache_setting_name='CACHE', cache_storage_setting_name='CACHE_STORAGE'):</p>
<p>即可以指明使用其它的配置名，这样就可以在你的settings.ini中存放不同的cache的配置，通过get_cache来使用不同的cache机制。</p>
<p>为什么要对Cache进行扩展，Cache.cache原来是针对函数本身和它的参数，但是这样对于view有一点问题。有些view可能通过QUERY_STRING来处理不同的传入参数，因此在url上它们不同，但是在view函数上是完全一样，因此这种只根据函数本身和参数是有问题的。因此扩展的page这个decorator使用了request.url值，它是一个完整的访问路径，包括了QUERY_STRING信息。因此为了生成静态cache，可以使用改造后的Cache类。当你调用get_cache()时返回的cache对象已经是使用了这个新的Cache类了。</p>
<p>所以为了方便和更适合在Uliweb环境下使用，可以使用uliweb.utils.cache的get_cache()函数。例如：</p>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top"> </td>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br>  2 <br>  3 <br>  4 <br>  5 <br>  6 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#0000ff"><strong>from</strong></font> <font color="#000000">uliweb</font><font color="#0000c0">.</font><font color="#000000">utils</font><font color="#0000c0">.</font><font color="#000000">cache</font> <font color="#0000ff"><strong>import</strong></font> <font color="#000000">get_cache</font><font color="#0000c0">(</font><font color="#0000c0">)</font><br><font color="#000000">cache</font> <font color="#0000c0">=</font> <font color="#000000">get_cache</font><font color="#0000c0">(</font><font color="#0000c0">)</font> <font color="#008000">#使用缺省的settings.ini设置。因此需要加入uliweb.contrib.cache这个app </font><br><font color="#0000c0">@</font><font color="#000000">cache</font><font color="#0000c0">.</font><font color="#000000">cache</font><font color="#0000c0">(</font><font color="#000000">expire</font><font color="#0000c0">=</font><font color="#0080c0">15</font><font color="#0000c0">)</font><br><font color="#0000c0">@</font><font color="#000000">expose</font><font color="#0000c0">(</font><font color="#804000">'/index'</font><font color="#0000c0">)</font><br><font color="#0000ff"><strong>def</strong></font> <font color="#000000">index</font><font color="#0000c0">(</font><font color="#0000c0">)</font><font color="#0000c0">:</font><br>    <font color="#0000ff"><strong>return</strong></font> <font color="#0000c0">{</font><font color="#0000c0">}</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
<p> </p>
<p>现在我把uliwebproject也添加了cache的支持，不过发现的问题是，不能简单的使用@cache.page()来对view方法进行处理。原因是：</p>
<p>在view方法中有对cookie的处理，采用cache的方式会屏蔽掉这块处理</p>
<p>因此在uliwebproject中并不是使用的decorator的方式，而是在view中对可以cache化的部分进行了手工处理，如：</p>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top"> </td>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br>  2 <br>  3 <br>  4 <br>  5 <br>  6 <br>  7 <br>  8 <br>  9 <br> 10 <br> 11 <br> 12 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#000000">cache</font> <font color="#0000c0">=</font> <font color="#000000">get_cache</font><font color="#0000c0">(</font><font color="#0000c0">)</font><br><font color="#0000c0">@</font><font color="#000000">cache</font><font color="#0000c0">.</font><font color="#000000">cache</font><font color="#0000c0">(</font><font color="#000000">_f</font><font color="#0000c0">)</font><br><font color="#0000ff"><strong>def</strong></font> <font color="#000000">f</font><font color="#0000c0">(</font><font color="#0000c0">)</font><font color="#0000c0">:</font><br>    <font color="#000000">content</font> <font color="#0000c0">=</font> <font color="#000000">file</font><font color="#0000c0">(</font><font color="#000000">_f</font><font color="#0000c0">)</font><font color="#0000c0">.</font><font color="#000000">read</font><font color="#0000c0">(</font><font color="#0000c0">)</font><br>    <font color="#0000ff"><strong>if</strong></font> <font color="#000000">render</font><font color="#0000c0">:</font><br>        <font color="#000000">content</font> <font color="#0000c0">=</font> <font color="#000000">to_html</font><font color="#0000c0">(</font><font color="#000000">template</font><font color="#0000c0">(</font><font color="#000000">content</font><font color="#0000c0">,</font> <font color="#000000">env</font><font color="#0000c0">=</font><font color="#000000">application</font><font color="#0000c0">.</font><font color="#000000">get_view_env</font><font color="#0000c0">(</font><font color="#0000c0">)</font><font color="#0000c0">)</font><font color="#0000c0">)</font><br>    <font color="#0000ff"><strong>else</strong></font><font color="#0000c0">:</font><br>        <font color="#000000">content</font> <font color="#0000c0">=</font> <font color="#000000">to_html</font><font color="#0000c0">(</font><font color="#000000">content</font><font color="#0000c0">)</font><br>    <font color="#0000ff"><strong>return</strong></font> <font color="#000000">application</font><font color="#0000c0">.</font><font color="#000000">template</font><font color="#0000c0">(</font><font color="#804000">'show_document.html'</font><font color="#0000c0">,</font> <font color="#000000">locals</font><font color="#0000c0">(</font><font color="#0000c0">)</font><font color="#0000c0">)</font><br><br><font color="#000000">response</font><font color="#0000c0">.</font><font color="#000000">write</font><font color="#0000c0">(</font><font color="#000000">f</font><font color="#0000c0">(</font><font color="#0000c0">)</font><font color="#0000c0">)</font><br><font color="#0000ff"><strong>return</strong></font> <font color="#000000">response</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
<div>完全是手工来处理了。</div>
</div>
</span> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/limodou/blog/category/Uliweb">Uliweb</a>&nbsp;<a href="http://hi.baidu.com/limodou/blog/item/294d09fa7030b69d59ee90dd.html#comment">查看评论</a>]]></description>
        <pubDate>2009-11-04  12:46</pubDate>
        <category><![CDATA[Uliweb]]></category>
        <author><![CDATA[limodou]]></author>
		<guid>http://hi.baidu.com/limodou/blog/item/294d09fa7030b69d59ee90dd.html</guid>
</item>

<item>
        <title><![CDATA[uliweb性能之优化思考]]></title>
        <link><![CDATA[http://hi.baidu.com/limodou/blog/item/12f14ec2af4a093fe5dd3bb0.html]]></link>
        <description><![CDATA[
		
		<span class="Apple-style-span" style="word-spacing: 0px; font: medium  YaHei Consolas Hybrid ; text-transform: none; color: rgb(0,0,0); text-indent: 0px; white-space: normal; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2; webkit-border-horizontal-spacing: 0px; webkit-border-vertical-spacing: 0px; webkit-text-decorations-in-effect: none; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px">
<div style="font-weight: normal; font-size: 14px; line-height: normal; font-style: normal;  background-color: rgb(255,255,255); background-origin: initial; background-clip: initial">
<p>性能与功能的确有些矛盾。因为开发uliweb更多是从功能上考虑，因此在性能上我一直没有太仔细测试和分析过。最近找了一个主机部署了一下，别人告诉我刷新一下CPU占用很高，于是我想有机会的确还是要好好搞一下。于是加了一些跟踪，发现了一些问题：</p>
<p>1. get_apps() 的问题</p>
<p>因为uliweb是采用app方式来组织，而且app是允许使用python的包形式。在启动时，为了查找app下的settings.ini和config.ini等信息，使用的是pkgresource的resource_filename，它是要导入才可以的。但是一个导入可能会使得加载变慢。这块的确有些问题。为了查找包的目录，因此要导入，但是后面的处理未必会使用这个包，显得有些浪费。因此我修改了这块处理。如果包是由a.b.c这样形式构成的，我会只导入a，后面两个直接根据a的目录生成一个路径。这样只要保证a的__init__.py中没有太多的耗时的代码就可以了。这样优化后减少了一些时间。</p>
<p>2. pytz的问题</p>
<p>因为uliweb的ORM会处理时区的问题，而且我写了一个utils/date.py模块专门来处理时区转换。因此在启动时，为了省事，我自动导入了date.py模块，它会自动导入pytz模块。但是我发现pytz的导入非常慢。这样造成整个uliweb的启动变慢。因此这块我直接去掉了，让用户自已来处理好了。</p>
<p>3. 可能会引起问题的地方。app的__init__.py文件。因为考虑有些bind的代码会写在__init__.py中，因此在启动app时会自动导入所有app。因此如果有app在这里写了很耗时的代码会影响整个uliweb的启动速度。也许你会认为不好，不过uliweb已经提供了许多静态化的方法，如：bind和expose可以静态化，即在settings.ini中进行配置，这样__init__.py中可以是空的。</p>
<p>这里的问题主要是由于方便性考虑产生的：采用自动化的方式，减少用户的导入或初始化的工作，结果使得处理范围扩大化，影响启动效率。</p>
<p>注意我说的主要是启动时的效率，一旦启动不退出，效率要好一些。</p>
<p>因此uliweb如果每次都是重新启动必然会造成性能下降，比较好的方式还是驻留式，不要每次启动。象mod_wsgi, fastcgi应该是可以支持的。是不是自带一个web server采用反向代理会更好呢？象java一样。</p>
</div>
</span> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/limodou/blog/category/Uliweb">Uliweb</a>&nbsp;<a href="http://hi.baidu.com/limodou/blog/item/12f14ec2af4a093fe5dd3bb0.html#comment">查看评论</a>]]></description>
        <pubDate>2009-11-02  22:16</pubDate>
        <category><![CDATA[Uliweb]]></category>
        <author><![CDATA[limodou]]></author>
		<guid>http://hi.baidu.com/limodou/blog/item/12f14ec2af4a093fe5dd3bb0.html</guid>
</item>

<item>
        <title><![CDATA[新的uliwiki项目]]></title>
        <link><![CDATA[http://hi.baidu.com/limodou/blog/item/6085b99992092e026e068cd0.html]]></link>
        <description><![CDATA[
		
		<span style="background-color: transparent; border-collapse: separate; color: rgb(0, 0, 0);  font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;" class="Apple-style-span">
<div style=" font-size: 14px; line-height: normal; font-style: normal; font-weight: normal; background-color: rgb(255, 255, 255);">
<p>今天开发了一个新的uliwiki的项目,不错是今天,我是照着<span class="Apple-converted-space">&#160;</span><span style="background-color: rgb(255, 255, 255);" mce_style="background-color: #ffffff; "><a target="_blank" mce_href="http://code.google.com/p/django-wikiapp/" href="http://code.google.com/p/django-wikiapp/">http://code.google.com/p/django-wikiapp/<span class="Apple-converted-space">&#160;</span></a>这个项目来做的,不过象界面,象处理许多都是重写的.因为原来的项目功能挺多,我目前还实现不了,比如:comment, tagging, notification, feed等.目前只是实现了一个基本的wiki的功能,用户认证还没有.但是wiki的功能基本上都全了:</span></p>
<p><span style="background-color: rgb(255, 255, 255);" mce_style="background-color: #ffffff; ">比如生成WikiWord链接,同时支持象[wiki:name message]的wikiword方式.</span></p>
<p>使用reStructuredText格式(目前只支持这一种)</p>
<p>编辑,删除,版本管理,恢复旧版本,查看旧版本.</p>
<p>其中版本管理我做得比较简单,我是每次保留全部内容,而不是增量内容,主要是为了方便生成版本差异.而django-wikiapp是保存的增量内容,因此处理上要复杂一些.</p>
<p>同时通过研究django-wikiapp发现了　<span class="Apple-converted-space">&#160;</span><span style="background-color: rgb(255, 255, 255);" mce_style="background-color: #ffffff; "><a target="_blank" mce_href="http://code.google.com/p/google-diff-match-patch/" href="http://code.google.com/p/google-diff-match-patch/">http://code.google.com/p/google-diff-match-patch/<span class="Apple-converted-space">&#160;</span></a>这个好东西,可以用来生成比较后的结果,并且还可以生成patch.</span></p>
<p>下面上几张图,看下效果:</p>
<p style="text-align: center;" mce_style="text-align:center;"><img style="border-width: 0px; width: 590px;" mce_src="http://photo.zeuux.com/photo/gallery/3910/original/" src="http://photo.zeuux.com/photo/gallery/3910/original/"></p>
<p style="text-align: center;" mce_style="text-align:center;">这是进入的首页面.</p>
<p style="text-align: center;" mce_style="text-align:center;"><img style="border-width: 0px; width: 590px;" mce_src="http://photo.zeuux.com/photo/gallery/3911/original/" src="http://photo.zeuux.com/photo/gallery/3911/original/"></p>
<p style="text-align: center;" mce_style="text-align:center;">这是某个页面的编辑页面</p>
<p style="text-align: center;" mce_style="text-align:center;"><img style="border-width: 0px;" mce_src="http://photo.zeuux.com/photo/gallery/3912/original/" src="http://photo.zeuux.com/photo/gallery/3912/original/"></p>
<p style="text-align: center;" mce_style="text-align:center;">这是版本信息,先选中不同的版本,然后点上面的Compare按钮可以显示下面的比较结果.</p>
<p style="text-align: center;" mce_style="text-align:center;"><img style="border-width: 0px; width: 590px;" mce_src="http://photo.zeuux.com/photo/gallery/3913/original/" src="http://photo.zeuux.com/photo/gallery/3913/original/"></p>
<p style="text-align: center;" mce_style="text-align:center;">这是使用了google-diff-match-patch显示的结果,还不错.</p>
<p style="text-align: left;" mce_style="text-align: left;">现在uliwiki的地址在　<span class="Apple-converted-space">&#160;</span><span style="background-color: rgb(255, 255, 255);" mce_style="background-color: #ffffff;"><a target="_blank" mce_href="http://code.google.com/p/uliwiki/" href="http://code.google.com/p/uliwiki/">http://code.google.com/p/uliwiki/<span class="Apple-converted-space">&#160;</span></a>&#160;有兴趣可以试试和完善它.</span></p>
</div>
</span> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/limodou/blog/category/Uliweb">Uliweb</a>&nbsp;<a href="http://hi.baidu.com/limodou/blog/item/6085b99992092e026e068cd0.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-18  21:32</pubDate>
        <category><![CDATA[Uliweb]]></category>
        <author><![CDATA[limodou]]></author>
		<guid>http://hi.baidu.com/limodou/blog/item/6085b99992092e026e068cd0.html</guid>
</item>

<item>
        <title><![CDATA[对《I have a dream》的回复]]></title>
        <link><![CDATA[http://hi.baidu.com/limodou/blog/item/9079bd3e7f3753f0828b13ca.html]]></link>
        <description><![CDATA[
		
		<span style="background-color: transparent; border-collapse: separate; color: rgb(0, 0, 0);  font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;" class="Apple-style-span"><span style=" font-size: 14px; line-height: 21px; text-align: left;" class="Apple-style-span">
<p style="margin: 1em 0px 0.5em; padding: 0px;">原文：&#160;<a style="text-decoration: none; color: rgb(0, 107, 173);" href="http://j-lite.net/blog/2009/10/17/i-have-a-dream">http://j-lite.net/blog/2009/10/17/i-have-a-dream</a></p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">以下是我的回复：</p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">我也不是为了争uliweb要比django强大，我也说了uliweb有自已的优势，而且我认为比django强的，但django也有它的优势。而且我也在邮件列表中多次声明，每个框架代表一种哲学，不同的哲学引来不同的用户，所以我离开django也可以说是我的哲学与django的哲学区别越来越多造成的。</p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">至于造轮的问题，因此我还是建议你有时间多了解一下uliweb。在今年9.5日的大会上我列举了自已创建的轮子的例子，比如：</p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">整个核心的处理完全是自已写的，它是一个框架的灵魂，负责整个框架的启动，组件管理(app管理)，配置管理，request和response处理，middleware的处理，这是每个框架不同于其它框架的核心，是无法复制的。如果只是简单的复制，那么这个框架存在的意义就没有了。其中整个app的详细支持是借鉴了django的思路，但是由我完善的。还有象view的处理，借鉴了web2py的思路，但是自已实现的。详细代码可以见uliweb.core.SimpleFrame.py.</p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">还有许多的模块是我自已写的：</p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">1. web2py的模板，已经被我改造增加了象编译文件目录支持，自定义tag支持，block的支持，这些都是原模板没有了，已经是uliweb化的组件了。<br>
2.dispatch模块，完全是自已写的，实现类似于django signal的功能。但是整个实现是从ulipad发展来的，没有照搬任何人的东西。<br>
3.i18n也是自已写的，是从ulipad发展来的。<br>
4.weto是在我发现beaker这个session库有问题之后重写的，完全是uliweb的东西。<br>
5.contrib下的所有组件都是我自已写的。<br>
6.pyini完全是自已构思创造出来的，用于处理uliweb的配置文件。<br>
7.orm这块是从头一点点构建的，也是一个框架很重要的部分。<br>
8.form库也是自已一点点写的。<br>
9.url映射的处理机制是使用了werkzeug的route为基础实现的，但是只是使用了它的基本功能，主要功能是uliweb实现的。</p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">一个框架主要完成的功能其实不外乎：url处理，request, response，view，orm，组件管理，配置管理，提供一些实用的扩展。因此，你可以看到，从架构设计，从组件的实现，许多方面都有uliweb自已的实现，甚至完全是uliweb自已的实现。因此从web2py，从django，从werkzeug，从sqlalchemy更多不是简单的引用，而是思想的借鉴，是更多的封装。</p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">所以，许多东西并不是简单了解就好象明白的。这是我想要澄清的地方。别人不认可uliweb没关系，很正常。但是我只是希望，评论一个东西首先要对它多少深入地了解一下，哪怕与作者交流一下也好，而是不看些表面。不仅从合理客观的角度来谈论一件事，更是不会误导别人。所以uliweb绝不是简单地组装出来的一个东西，它有自已特性甚至独一无二的东西。许多人一谈uliweb，就是从重装造轮的角度，但是他们并不了解许多uliweb上的设计的东西，也基本上没有在技术细节上的讨论，谈得很泛泛。这样对谁都不是公平的。</p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">你所说的框架其实目前pylons和tg都差不多，而uliweb也是可以，django也是可以，只不过pylons和tg可能从组件上可以直接选择，而uliweb,django是可以自已定制开发，不能直接使用。而且你所说的更接近于某些人更偏重于自已去建，比如这篇文章：</p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">http://pythonpaste.org/webob/do-it-yourself.html</p>
<p style="margin: 1em 0px 0.5em; padding: 0px;">自已建是没有问题。因此框架更多是给那些不希望，甚至不能够自已来做这件事的人准备的。但是自已建，可能需要了解的东西更多，正如我在构建uliweb过程中，我学到了比以前简单使用框架更多的东西，我甚至做了许多以前不知道自已还可以做的事情。各有各的乐趣。</p>
</span></span> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/limodou/blog/category/Uliweb">Uliweb</a>&nbsp;<a href="http://hi.baidu.com/limodou/blog/item/9079bd3e7f3753f0828b13ca.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-18  10:41</pubDate>
        <category><![CDATA[Uliweb]]></category>
        <author><![CDATA[limodou]]></author>
		<guid>http://hi.baidu.com/limodou/blog/item/9079bd3e7f3753f0828b13ca.html</guid>
</item>

<item>
        <title><![CDATA[关于Webob无法支持flash文件上传问题的记录]]></title>
        <link><![CDATA[http://hi.baidu.com/limodou/blog/item/7a7fb58f3a6dc9e4f01f3681.html]]></link>
        <description><![CDATA[
		
		<em>根据邮件列表中的回复加工</em><br>
<br>
1. 提出问题：<br>
<br>
使用webob在处理通过fancyupload上传的文件，发现会系统挂起，但只要先把request.body读出来就没有问题。因此在uliweb中，将原来使用的webob去除，改成了werkzeug来处理了。<br>
<br>
2. qiangninghong的试验：<br>
<br>
因为limodou反应的这个问题认为是cgi模块有bug导致的，所以很重要。今天晚上稍稍有点时间，写了一个测试程序来验证一下，但是发现似乎没有这样的情况？<br>
<br>
测试代码在这里 http://code.google.com/p/hongqnlib/source/browse/<br>
<br>
就是照着 FancyUpload 的 Attach File demo 页面 ( http://digitarald.de/project/fancyupload/3-0/showcase/attach-a-file/ ) 翻译了一下。运行 server.py 后，访问 http://localhost:5002/ ，上传了几个文件，都没有出现挂住的情况啊？<br>
<br>
难道是我的这个测试有什么问题？请 limodou 帮忙看看。<br>
<br>
3. 我的试验：<br>
<br>
我把你的程序改了一下：<br>
<br>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top"> </td>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br>  2 <br>  3 <br>  4 <br>  5 <br>  6 <br>  7 <br>  8 <br>  9 <br> 10 <br> 11 <br> 12 <br> 13 <br> 14 <br> 15 <br> 16 <br> 17 <br> 18 <br> 19 <br> 20 <br> 21 <br> 22 <br> 23 <br> 24 <br> 25 <br> 26 <br> 27 <br> 28 <br> 29 <br> 30 <br> 31 <br> 32 <br> 33 <br> 34 <br> 35 <br> 36 <br> 37 <br> 38 <br> 39 <br> 40 <br> 41 <br> 42 <br> 43 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#0000ff"><strong>import</strong></font> <font color="#000000">os</font><br><font color="#0000ff"><strong>import</strong></font> <font color="#000000">mimetypes</font><br><font color="#0000ff"><strong>import</strong></font> <font color="#000000">time</font><br><font color="#0000ff"><strong>import</strong></font> <font color="#000000">socket</font><br><font color="#0000ff"><strong>from</strong></font> <font color="#000000">hashlib</font> <font color="#0000ff"><strong>import</strong></font> <font color="#000000">md5</font><br><font color="#0000ff"><strong>import</strong></font> <font color="#000000">simplejson</font> <font color="#0000ff"><strong>as</strong></font> <font color="#000000">json</font><br><font color="#0000ff"><strong>import</strong></font> <font color="#000000">webob</font><font color="#0000c0">,</font> <font color="#000000">webob</font><font color="#0000c0">.</font><font color="#000000">exc</font><br><font color="#0000ff"><strong>from</strong></font> <font color="#000000">paste</font><font color="#0000c0">.</font><font color="#000000">urlparser</font> <font color="#0000ff"><strong>import</strong></font> <font color="#000000">StaticURLParser</font><br><font color="#0000ff"><strong>from</strong></font> <font color="#000000">paste</font><font color="#0000c0">.</font><font color="#000000">cascade</font> <font color="#0000ff"><strong>import</strong></font> <font color="#000000">Cascade</font><br><font color="#0000ff"><strong>import</strong></font> <font color="#000000">logging</font><br><font color="#0000ff"><strong>from</strong></font> <font color="#000000">paste</font> <font color="#0000ff"><strong>import</strong></font> <font color="#000000">fileapp</font><br><br><br><font color="#0000ff"><strong>def</strong></font> <font color="#000000">app</font><font color="#0000c0">(</font><font color="#000000">environ</font><font color="#0000c0">,</font> <font color="#000000">start_response</font><font color="#0000c0">)</font><font color="#0000c0">:</font><br>   <font color="#000000">request</font> <font color="#0000c0">=</font> <font color="#000000">webob</font><font color="#0000c0">.</font><font color="#000000">Request</font><font color="#0000c0">(</font><font color="#000000">environ</font><font color="#0000c0">)</font><br>   <font color="#0000ff"><strong>if</strong></font> <font color="#000000">request</font><font color="#0000c0">.</font><font color="#000000">method</font> <font color="#0000c0">==</font> <font color="#804000">'GET'</font><font color="#0000c0">:</font><br>       <font color="#000000">filename</font> <font color="#0000c0">=</font> <font color="#000000">request</font><font color="#0000c0">.</font><font color="#000000">path_info</font><font color="#0000c0">.</font><font color="#000000">lstrip</font><font color="#0000c0">(</font><font color="#804000">'/'</font><font color="#0000c0">)</font><br>       <font color="#000000">response</font> <font color="#0000c0">=</font> <font color="#000000">fileapp</font><font color="#0000c0">.</font><font color="#000000">FileApp</font><font color="#0000c0">(</font><font color="#000000">filename</font><font color="#0000c0">)</font><br>   <font color="#0000ff"><strong>else</strong></font><font color="#0000c0">:</font><br><font color="#008000">#        logging.error( repr(request.body))<br></font>       <font color="#000000">filedata</font> <font color="#0000c0">=</font> <font color="#000000">request</font><font color="#0000c0">.</font><font color="#000000">POST</font><font color="#0000c0">[</font><font color="#804000">'Filedata'</font><font color="#0000c0">]</font><br>       <font color="#000000">r</font> <font color="#0000c0">=</font> <font color="#000000">dict</font><font color="#0000c0">(</font><font color="#000000">status</font><font color="#0000c0">=</font><font color="#804000">'1'</font><font color="#0000c0">,</font> <font color="#000000">name</font><font color="#0000c0">=</font><font color="#000000">filedata</font><font color="#0000c0">.</font><font color="#000000">filename</font><font color="#0000c0">)</font><br>       <font color="#000000">text</font> <font color="#0000c0">=</font> <font color="#000000">filedata</font><font color="#0000c0">.</font><font color="#000000">file</font><font color="#0000c0">.</font><font color="#000000">read</font><font color="#0000c0">(</font><font color="#0000c0">)</font><br>       <font color="#000000">r</font><font color="#0000c0">[</font><font color="#804000">'hash'</font><font color="#0000c0">]</font> <font color="#0000c0">=</font> <font color="#000000">md5</font><font color="#0000c0">(</font><font color="#000000">text</font><font color="#0000c0">)</font><font color="#0000c0">.</font><font color="#000000">hexdigest</font><font color="#0000c0">(</font><font color="#0000c0">)</font><br>       <font color="#0000ff"><strong>if</strong></font> <font color="#000000">request</font><font color="#0000c0">.</font><font color="#000000">params</font><font color="#0000c0">.</font><font color="#000000">get</font><font color="#0000c0">(</font><font color="#804000">'response'</font><font color="#0000c0">)</font> <font color="#0000c0">==</font> <font color="#804000">'xml'</font><font color="#0000c0">:</font><br>           <font color="#000000">response</font> <font color="#0000c0">=</font> <font color="#000000">webob</font><font color="#0000c0">.</font><font color="#000000">Response</font><font color="#0000c0">(</font><font color="#000000">content_type</font><font color="#0000c0">=</font><font color="#804000">'text/xml'</font><font color="#0000c0">)</font><br>           <font color="#0000ff"><strong>print</strong></font> <font color="#0000c0">&gt;&gt;</font><font color="#000000">response</font><font color="#0000c0">.</font><font color="#000000">body_file</font><font color="#0000c0">,</font> <font color="#804000">'&lt;response&gt;'</font><br>           <font color="#0000ff"><strong>for</strong></font> <font color="#000000">k</font><font color="#0000c0">,</font> <font color="#000000">v</font> <font color="#0000ff"><strong>in</strong></font> <font color="#000000">r</font><font color="#0000c0">.</font><font color="#000000">items</font><font color="#0000c0">(</font><font color="#0000c0">)</font><font color="#0000c0">:</font><br>               <font color="#0000ff"><strong>print</strong></font> <font color="#0000c0">&gt;&gt;</font><font color="#000000">response</font><font color="#0000c0">.</font><font color="#000000">body_file</font><font color="#0000c0">,</font> \<br>                       <font color="#804000">&quot;&lt;%(k)s&gt;&lt;![CDATA[%(v)s]]&gt;&lt;/%(k)s&gt;&quot;</font> <font color="#0000c0">%</font> <font color="#000000">locals</font><font color="#0000c0">(</font><font color="#0000c0">)</font><br>           <font color="#0000ff"><strong>print</strong></font> <font color="#0000c0">&gt;&gt;</font><font color="#000000">response</font><font color="#0000c0">.</font><font color="#000000">body_file</font><font color="#0000c0">,</font> <font color="#804000">'&lt;/response&gt;'</font><br>       <font color="#0000ff"><strong>else</strong></font><font color="#0000c0">:</font><br>           <font color="#000000">response</font> <font color="#0000c0">=</font> <font color="#000000">webob</font><font color="#0000c0">.</font><font color="#000000">Response</font><font color="#0000c0">(</font><font color="#000000">content_type</font><font color="#0000c0">=</font><font color="#804000">'application/json'</font><font color="#0000c0">,</font><br>                                     <font color="#000000">body</font><font color="#0000c0">=</font><font color="#000000">json</font><font color="#0000c0">.</font><font color="#000000">dumps</font><font color="#0000c0">(</font><font color="#000000">r</font><font color="#0000c0">)</font><font color="#0000c0">)</font><br>   <font color="#0000ff"><strong>return</strong></font> <font color="#000000">response</font><font color="#0000c0">(</font><font color="#000000">environ</font><font color="#0000c0">,</font> <font color="#000000">start_response</font><font color="#0000c0">)</font><br><br><font color="#008000">#static_app = StaticURLParser('/static')<br></font><font color="#008000">#app = Cascade([static_app, app], (404, 405))<br></font><br><font color="#0000ff"><strong>if</strong></font> <font color="#000000">__name__</font> <font color="#0000c0">==</font> <font color="#804000">'__main__'</font><font color="#0000c0">:</font><br>   <font color="#0000ff"><strong>from</strong></font> <font color="#000000">wsgiref</font><font color="#0000c0">.</font><font color="#000000">simple_server</font> <font color="#0000ff"><strong>import</strong></font> <font color="#000000">make_server</font><br>   <font color="#000000">server</font> <font color="#0000c0">=</font> <font color="#000000">make_server</font><font color="#0000c0">(</font><font color="#804000">'localhost'</font><font color="#0000c0">,</font> <font color="#0080c0">5002</font><font color="#0000c0">,</font> <font color="#000000">app</font><font color="#0000c0">)</font><br>   <font color="#000000">server</font><font color="#0000c0">.</font><font color="#000000">serve_forever</font><font color="#0000c0">(</font><font color="#0000c0">)</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
分析如下：<br>
<br>
1. 使用你的程序的确没有问题，使用我改的程序就有问题<br>
2. 两个差别在于你在调用处理前使用了一个StaticURLParser，而我改后的程序是不使用它，在app中自已处理。这样的目的并不是使用StaticURLParser不行，而是这样的做法其实是在app处理前多了一层处理，那么这层处理会影响后面的处理，掩盖问题的发生。<br>
3. 在我的例子中，只要把#&#160;&#160;&#160;&#160;&#160;&#160;&#160; logging.error( repr(request.body))这行的注释去了，程序就正常。<br>
4. 原因就是，只要你想办法在执行request.POST['Filedata']之前执行了象request.body之类的代码，这样会引起对body的整个读取，这时读取是按Content-Length来处理的，并且会放在缓冲区中，因此后续的处理就是从这个缓冲区来的了，因此缓冲区最后有没有回车换行是没有关系的。而使用flash控件上传文件，文件体示例如下：<br>
<br>
ERROR:root:'------------ei4GI3ei4Ef1Ef1GI3ei4Ij5GI3GI3\r\nContent-Disposition:<br>
form-data; name=&quot;Filename&quot;\r\n\r\na.c\r\n------------ei4GI3ei4Ef1Ef1GI3ei4Ij5GI3G<br>
I3\r\nContent-Disposition: form-data; name=&quot;Filedata&quot;;<br>
filename=&quot;a.c&quot;\r\nContent-Type:<br>
application/octet-stream\r\n\r\n#include<br>
&lt;stdio.h&gt;\r\n\r\n------------ei4<br>
GI3ei4Ef1Ef1GI3ei4Ij5GI3GI3\r\nContent-Disposition: form-data;<br>
name=&quot;Upload&quot;\r\n\r\nSubmit<br>
Query\r\n------------ei4GI3ei4Ef1Ef1GI3ei4Ij5GI3GI3--'<br>
<br>
可以看到，最后是没有\r\n的。这不是浏览器的问题，是flash组件本身的问题，相关的flash的类本身的问题。但其实也不算一个问题，因为cgi的处理是基于multipart的boundary需要以\r\n结束这个假设，但这种假设在某些情况下有问题。相应的cgi的代码如下（从cgi.py中找到的703行）：<br>
<br>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top"> </td>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br>  2 <br>  3 <br>  4 <br>  5 <br>  6 <br>  7 <br>  8 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#0000ff"><strong>def</strong></font> <font color="#000000">read_lines_to_eof</font><font color="#0000c0">(</font><font color="#000000">self</font><font color="#0000c0">)</font><font color="#0000c0">:</font><br>   <font color="#804000">&quot;&quot;&quot;Internal: read lines until EOF.&quot;&quot;&quot;</font><br>   <font color="#0000ff"><strong>while</strong></font> <font color="#0080c0">1</font><font color="#0000c0">:</font><br>       <font color="#000000">line</font> <font color="#0000c0">=</font> <font color="#000000">self</font><font color="#0000c0">.</font><font color="#000000">fp</font><font color="#0000c0">.</font><font color="#000000">readline</font><font color="#0000c0">(</font><font color="#0080c0">1</font><font color="#0000c0">&lt;&lt;</font><font color="#0080c0">16</font><font color="#0000c0">)</font><br>       <font color="#0000ff"><strong>if</strong></font> <font color="#0000ff"><strong>not</strong></font> <font color="#000000">line</font><font color="#0000c0">:</font><br>           <font color="#000000">self</font><font color="#0000c0">.</font><font color="#000000">done</font> <font color="#0000c0">=</font> <font color="#0000c0">-</font><font color="#0080c0">1</font><br>           <font color="#0000ff"><strong>break</strong></font><br>       <font color="#000000">self</font><font color="#0000c0">.</font><font color="#000000">__write</font><font color="#0000c0">(</font><font color="#000000">line</font><font color="#0000c0">)</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
就是这个readline造成的，如果没有\r\n它根本不会返回。<br>
<br>
因此前面的问题就是，如果不先执行request.body，则后面的request.POST['Filedata']会从流中进行读取，而不是缓冲区中，但flash正好又不返回\r\n，因此server在使用readline就停处了，造成挂起，进而引发浏览器的flash控件的超时。<br>
<br>
而你的例子使用了StaticURLParser，可能会进行request.body的读取，所以掩盖了这个问题。当然它到底怎么做的，我没有继续深究。因此我改了你的程序，就是为了不让其它的因素干扰，问题就暴露出来了。<br> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/limodou/blog/category/Uliweb">Uliweb</a>&nbsp;<a href="http://hi.baidu.com/limodou/blog/item/7a7fb58f3a6dc9e4f01f3681.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-17  11:09</pubDate>
        <category><![CDATA[Uliweb]]></category>
        <author><![CDATA[limodou]]></author>
		<guid>http://hi.baidu.com/limodou/blog/item/7a7fb58f3a6dc9e4f01f3681.html</guid>
</item>

<item>
        <title><![CDATA[Uliweb中ORM的新变化]]></title>
        <link><![CDATA[http://hi.baidu.com/limodou/blog/item/d5c135a89aa3d4bbca130c4c.html]]></link>
        <description><![CDATA[
		
		最近一段时间一直在忙着ORM的优化，其中有几点：<br>
<br>
1.增加__table_args__的配置。它和__tablename__一样是定义在Model类中的，可以用来增加在执行Table时添加新的一些参数，如果你使用mysql，可以如下定义：<br>
<br>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br>  2 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#0000ff"><strong>class</strong></font> <font color="#000000">Todo</font><font color="#0000c0">(</font><font color="#000000">Model</font><font color="#0000c0">)</font><font color="#0000c0">:</font><br>    <font color="#000000">__table_args__</font> <font color="#0000c0">=</font> <font color="#000000">dict</font><font color="#0000c0">(</font> <font color="#000000">mysql_engine</font><font color="#0000c0">=</font><font color="#804000">'InnoDB'</font><font color="#0000c0">,</font> <font color="#000000">mysql_charset</font><font color="#0000c0">=</font><font color="#804000">'utf8'</font><font color="#0000c0">)</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
这样将在建表时，向Table中添加这样的信息。上面的代码将以InnoDB和utf8编码来创建todo表。<br>
<br>
2.增加OnInit类方法的调用。这个方法是交给用户来定义的，可以用来执行在执行完Table之后的一些初始化操作，它将在建表之前。比如：<br>
<br>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top"> </td>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br>  2 <br>  3 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#0000c0">@</font><font color="#000000">classmethod</font><br><font color="#0000ff"><strong>def</strong></font> <font color="#000000">OnInit</font><font color="#0000c0">(</font><font color="#000000">cls</font><font color="#0000c0">)</font><font color="#0000c0">:</font><br>    <font color="#000000">Index</font><font color="#0000c0">(</font><font color="#804000">'my_indx'</font><font color="#0000c0">,</font> <font color="#000000">cls</font><font color="#0000c0">.</font><font color="#000000">c</font><font color="#0000c0">.</font><font color="#000000">title</font><font color="#0000c0">,</font> <font color="#000000">cls</font><font color="#0000c0">.</font><font color="#000000">c</font><font color="#0000c0">.</font><font color="#000000">owner</font><font color="#0000c0">,</font> <font color="#000000">unique</font><font color="#0000c0">=</font><font color="#000000">True</font><font color="#0000c0">)</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
这样将创建以title, owner的索引，并且索引不允许重复。目前只支持索引的创建。对于简单的索引，是可以在定义Field时直接设置index=True来创建的，并不需要这种方式。这种方式可以认为就是为了创建多个字段的联合索引。<br>
<br>
3.考虑缺省order_by的实现。但是想用户完全可以在Model中定义相应的方法来实现，类似于django的Manager的东西，比如：<br>
<br>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top"> </td>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br>  2 <br>  3 <br>  4 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#0000ff"><strong>class</strong></font> <font color="#000000">Todo</font><font color="#0000c0">(</font><font color="#000000">Model</font><font color="#0000c0">)</font><font color="#0000c0">:</font><br>    <font color="#0000c0">@</font><font color="#000000">classmethod</font><br>    <font color="#0000ff"><strong>def</strong></font> <font color="#000000">files</font><font color="#0000c0">(</font><font color="#000000">cls</font><font color="#0000c0">)</font><font color="#0000c0">:</font><br>        <font color="#0000ff"><strong>return</strong></font> <font color="#000000">cls</font><font color="#0000c0">.</font><font color="#000000">all</font><font color="#0000c0">(</font><font color="#0000c0">)</font><font color="#0000c0">.</font><font color="#000000">order_by</font><font color="#0000c0">(</font><font color="#000000">cls</font><font color="#0000c0">.</font><font color="#000000">c</font><font color="#0000c0">.</font><font color="#000000">title</font><font color="#0000c0">.</font><font color="#000000">desc</font><font color="#0000c0">(</font><font color="#0000c0">)</font><font color="#0000c0">)</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
然后在使用时可以通过Todo.files()来返回按title降序排列的结果。所以使用这种方法倒是不一定要支持缺省order_by的配置项。不过有这个配置项的好处就是当需要实现通用的查询时，它可以自动生效。不过也可以考虑把结果集当成一个参数传给配置功能，总之还是有方法。<br>
<br>
4.最重要的一个特性。增加表的注册，并且注册的表不一定是一个Model，而是一个模块名的形式，如以下两种都是正确的注册方式：<br>
<br>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top"> </td>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br>  2 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#000000">set_model</font><font color="#0000c0">(</font><font color="#000000">Model</font><font color="#0000c0">,</font> <font color="#000000">tablename</font><font color="#0000c0">=</font><font color="#804000">'user'</font><font color="#0000c0">)</font><br><font color="#000000">set_model</font><font color="#0000c0">(</font><font color="#804000">'uliweb.contrib.auth.models.User'</font><font color="#0000c0">,</font> <font color="#000000">tablename</font><font color="#0000c0">=</font><font color="#804000">'user'</font><font color="#0000c0">)</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
这样注册之后，你就可以通过使用真正的表名来得到对应的Model类对象了。通过：<br>
<br>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top"> </td>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#000000">User</font> <font color="#0000c0">=</font> <font color="#000000">get_model</font><font color="#0000c0">(</font><font color="#804000">'user'</font><font color="#0000c0">)</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
这种方式首先可以使用在关系的定义中，如：<br>
<br>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top"> </td>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br>  2 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#000000">Reference</font><font color="#0000c0">(</font><font color="#804000">'user'</font><font color="#0000c0">)</font><br><font color="#000000">ManyToMany</font><font color="#0000c0">(</font><font color="#804000">'user'</font><font color="#0000c0">)</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
对于关系定义，它可以根据表名自动导入对应的Model。而对于在程序中想直接使用某个Model，则可以通过get_model()来获取。<br>
<br>
但是这种get_model()的方式要依赖于set_model()的注册过程。注册有几种方式：<br>
<br>
1. 在导入Model文件时，随着Model的class的创建自动会调用set_model()来注册，因此只要正常导入相应的模块，就可以使用get_model()方法了。这种情况下，对通常的开发没有什么影响，用户甚至不必使用这种方式。<br>
<br>
2. 由框架来注入。也就是uliweb来实现。这种方式首先要求将Model信息写入到settings.ini中，比如：<br>
<br>
<table border="0">
    <tbody>
        <tr>
            <td align="right" valign="top"> </td>
            <td align="right" valign="top">
            <pre><font face="Lucida,Courier New" color="#000000">  1 <br>  2 <br></font></pre>
            </td>
            <td valign="top">
            <pre><font face="Lucida,Courier New"><font color="#0000c0">[</font><font color="#000000">MODELS</font><font color="#0000c0">]</font><br><font color="#000000">user</font> <font color="#0000c0">=</font> <font color="#804000">'uliweb.contrib.auth.models.User'</font></font></pre>
            </td>
        </tr>
    </tbody>
</table>
这样当uliweb在启动时可以自动采集注册信息。然后在orm这个app的__init__.py中执行真正的注册工作，通过调用set_model()方法。这时，注册的就不是Model了，而是字符串形式的信息。<br>
<br>
然后在某个地方，如views.py中使用get_model()或导入models.py时，就可以自动生效了。<br>
<br>
你可能会问，这有什么用呢？一般不都是直接导入来使用吗？完全够用了。<br>
<br>
的确，一般的程序的确是根本用不上。但是Uliweb是一个框架，它要考虑代码的复用和替换的问题。考虑一下，在你的models.py可能需要对User表进行处理，那么你会去导入它。但是有可能这个User表不适合你的应用了，你怎么办？并且这个User表不是你自已写的，而是框架或别人提供的，别人可能还要依赖于这个表。因此简单的直接修改并不一定是好办法，因为它可能不受你的控制。重新写一个可能是好办法，但是因为直接导入的原因，比如你是通过：<br>
<pre><font face="Lucida,Courier New"><font color="#0000ff"><strong>from</strong></font> <font color="#000000">uliweb</font><font color="#0000c0">.</font><font color="#000000">contrib</font><font color="#0000c0">.</font><font color="#000000">auth</font><font color="#0000c0">.</font><font color="#000000">models</font> <font color="#0000ff"><strong>import</strong></font> <font color="#000000">User</font></font></pre>
这可是直接hard code了，所以重新写必然还要修改导入的代码。那么要解决这个问题，可以采用的一种办法就是将外部依赖的内容配置化，和java中的注入依赖有些象。也就是我在定义自已的东西时，可能需要外部的东西，那么我并不直接导入，而是通过一种获取的方式来得到。这样工并不需要知道外部的组件的实际位置，这件事由框架来完成。因此uliweb现在实现的get_model就是为了实现这一配置化而设计的。<br>
<br>
其实现在，象bind，expose都已经是可以配置化的了，都可以放在settings.ini中。如果完全配置化，将可以减少启动时的导入处理，并且替换会很容易。 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/limodou/blog/category/Uliweb">Uliweb</a>&nbsp;<a href="http://hi.baidu.com/limodou/blog/item/d5c135a89aa3d4bbca130c4c.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-15  21:38</pubDate>
        <category><![CDATA[Uliweb]]></category>
        <author><![CDATA[limodou]]></author>
		<guid>http://hi.baidu.com/limodou/blog/item/d5c135a89aa3d4bbca130c4c.html</guid>
</item>

<item>
        <title><![CDATA[pyini.py的新功能]]></title>
        <link><![CDATA[http://hi.baidu.com/limodou/blog/item/88483801857fe1047bec2c88.html]]></link>
        <description><![CDATA[
		
		<span style="background-color: transparent; border-collapse: separate; color: rgb(0, 0, 0);  font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;" class="Apple-style-span">
<div style="margin: 8px; color: rgb(0, 0, 0);  font-size: 12px; background-color: rgb(255, 255, 255);">
<div>
<p style="margin: 0px; padding: 0px;">pyini.py是处理Uliweb的settings.ini的模块，今天向它添加了三个新的方法：set_var, get_var, del_var，它们的特点集中在第一个参数，它可以是'/'分开的字符串，如：'DEFAULT/flag'，它相当于：</p>
<p style="margin: 0px; padding: 0px;">s = ini.add('DEFAULT')&#160;<br>
s['flag'] = True&#160;</p>
<p style="margin: 0px; padding: 0px;">注意，它只支持一层的'/'切分，如：'DEFAULT/flag/name'相当于 'DEFAULT'和'flag/name'。</p>
</div>
</div>
</span> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/limodou/blog/category/Uliweb">Uliweb</a>&nbsp;<a href="http://hi.baidu.com/limodou/blog/item/88483801857fe1047bec2c88.html#comment">查看评论</a>]]></description>
        <pubDate>2009-10-15  20:18</pubDate>
        <category><![CDATA[Uliweb]]></category>
        <author><![CDATA[limodou]]></author>
		<guid>http://hi.baidu.com/limodou/blog/item/88483801857fe1047bec2c88.html</guid>
</item>


</channel>
</rss>