2008年06月08日

在百度申请了一个新的Blog,以后有些什么东西可能就写在那里面了。

http://hi.baidu.com/limodou

不知道是不是被黑了,在网上查了查的确有这样的情况。所以目前是已经无法登录,密码已经被修改掉了。以前的邮箱也不记得了,因为时间太久了。

正在进行密码找回,不知道是否可以成功。所以暂时 limodou@gmail.com 不能用了。需要联系先发到 limodou.mail@gmail.com 邮箱吧。

看一看能不能恢复吧,不能恢复的话只有换了。

2008年06月07日

很简单,但是可以领略Uliweb的风采。

阅读地址: http://uliwebproject.appspot.com/documents/hello_uliweb

其实 Uliwebproject 本身就是使用Uliweb构建的,只不过目前还没有使用到数据库的东西,文档都是使用reStructuredText+pygments动态生成的。

2008年06月04日

uliweb 现在我部署在了 GAE 上了。不过目前还没有使用数据库,而且uliweb目前还没有与任何ORM绑定。

访问地址: http://uliwebproject.appspot.com
文档还不全,我会慢慢补齐。另外会慢慢完善它。

目前uliweb的网站使用了docutils,不过你不能直接使用它。可以在:

svn co http://mymisc.googlecode.com/svn/trunk/ulipad_appspot ulipad_appspot

找到我修改的版本,同时还有pygments包。

2008年05月30日

Kelie Feng制作的UliPad介绍的视频,现在可以在Showmedo网站上看到了。

观看地址在 http://showmedo.com/videos/series?name=ZODUqnEaL

另外Dick Moores将原始的视频放在了他的网站上可以下载 http://www.rcblue.com/u3/Introducing_Ulipad_2008-05-22.avi

感谢Kelie Feng和Dick Moores的努力和宣传。

2008年05月21日

今天zoom.quiet给项目起了一个新名字,叫uliweb,不过他宣传得很大,对于我只想先测试一些web框架方面的想法,当然如果有人愿意用是最好的。同时邀请了ygao加入了项目。目前已经有:我,zoom.quiet, ygao, 刘鑫。项目已经建立了 http://code.google.com/p/uliweb 同时建立了邮件列表 http://groups.google.com/group/uliweb。所以以后有什么问题或建议关于uliweb的,都可以在这个邮件列表中讨论。当然在python-cn邮件列表还可以讨论。如果你感兴趣欢迎随时加入。如果你对trunk版本不满意,可以随意创建自已的分支,对于可以合并到trunk中的代码我想需要小心处理。

目前正在使用uliweb来改造以前的 http://ulipad.appspot.com 项目。因为以前ulipad.appspot没有使用任何框架,模板使用的是web2py的,所以已经很接近现在的uliweb了,改动主要集中在view的替换上。工作正在进行中。

2008年05月20日

现在最新版的kuaiboo(需要从svn中获得)已经可以运行在GAE上了。不过我还没有在真正的环境下测试,只是在dev环境下试的。步骤如下:

1. 从svn中取得最新的版本

2. 使用export导出到一个目录下,可以直接导出到google的开发目录下。我的目录为:C:\Program Files\Google\google_appengine

3. 修改app.yaml和kuaoboo文件夹的名称为你想要的项目名称

4. 启动GAE的测试服务器可以开始运行。应该可以进入Hello这个测试环境中。

目前kuaiboo因为很简单,所以没有数据库的东西,你可以直接使用GAE的数据库接口。不过对于一个框架来说,数据库是一个很微妙的东西。我想在想它未必一定要做为核心组件。

不过在开始在GAE上测试时出现问题,在views导入时提示expose不存在。因为我是将其放在__builtin__中的,本来在一般的Python环境下应该是可以当成内置函数直接使用的,但是好象GAE给处理掉了,不起作用,最后还是使用了

from frameworks.SimpleFrame import expose

这种方式解决了问题。但是在非GAE环境下还是不需要导入的。不过对于在view函数中注入func_globals的方法还是没有问题。有兴趣的试一试吧。

2008年05月17日

更新记录:

1. 增加静态文件的支持。目前你只要在任何一个views文件中增加以下内容:

from frameworks.SimpleFrame import static_serve
@expose(‘/static/<regex(".*$"):filename>’)
def static(filename):
    return static_serve(request, filename)

这样一旦你的链接是/static/filename时,kuaiboo会自动查找所有app下的static文件夹,如果找到则返回这个文件。这里expose可以使用<regex("pattern"):argu_name>的形式进行正则式的匹配。注意正则式需要使用双引号引起来。这个静态文件处理支持条件返回,即如果文件没有改变,则返回304,文件将不会下传。同时支持406 Partial Content下传,可以支持分块下传。当然这些是webob已经提供的,同时参考了webob的这篇文档。因此实现已经很方便。这样在你刷新时,如果静态文件已经下传,再刷新时,会在console的日志中看到304。不错。

一旦部署到生产上,你可能会想使用web server来做静态文件的处理,没问题。只要将所有app下的static文件汇总到一起,统一由web server提供服务就可以了。这个汇总工具还没有做,以后再说,很简单。

2. 扩展werkzeug的URL Converter,扩展了一个正则式的Converter,可以从上例看到。

3. 扩展views函数的func_globals内容,现在有:

    def _prepare_env(self):
        env = {}
        env['url_for'] = url_for
        env['redirect'] = redirect
        env['url_map'] = url_map
        env['render'] = self.render
        env['config'] = config
        from werkzeug import html, xhtml
        env['html'] = html
        env['xhtml'] = xhtml
        from utils import Form
        env['Form'] = Form
        return env
       
    def get_env(self, request, response):
        env = self.env.copy()
        env['request'] = request
        env['response'] = response
        return env

以上在env中的key对应的对象都是你可以直接在views函数中使用的。

4. 将expose放到__builtin__模块中,这样在views文件中,你不需要导入这个函数,可以直接使用,就象是使用内置函数一样。可以减少不必要的导入。目前我只放入了这个。

5. 在request创建后,将appname和function绑定到request对象上,因此你可以直接使用request.appname得到views函数对应的app名字。这样当使用url_for来生成url时,一般是这样的:

url_for(‘Hello.views.index’, **kw)

但这样你的appname是写死的,这里是Hello,但如果你的app改名了怎么办,那么现在可以使用:

url_for(‘%s.views.index’ % request.appname, **kw)

现在你在Hello App中的index.html可以看到这种用法。

6. 增加了一个default_config,将用来放置一些缺省的配置。同时将settings改为config了。这样你可以使用config来读取配置在settings中的信息。它是一个Storage对象。这个Storage是从web2py中弄过来的,它就是一个dict,但是可以使用obj.attr的方式来引用key,同时如果不存在则返回None。那么你使用起来就和Module差不多了。但是对不存在的变量不会抛异常。同时所有配置项需要大写,这一点与django相同。

7. 在views你可以调用redirect(url)来进行转换。原来需要使用return,现在只要调用就行了。它会引发一个异常,并且被Dispatcher处理。

8. 在views中还可以使用error(**kw)来引发一个错误,它会自动调用一个错误模板,同时你也可以自已来指定出错模板。它也会引发一个异常,并且被Dispatcher来处理。

更新说明:

  1. 用户可以设定settings.py。目前kuaiboo支持在apps目录下的settings.py文件和每个app目录下的settings.py。目前apps的settings.py作为主配置文件,kuaiboo会直接导入,其它的app下的settings.py会使用__import__,然后将属性合并到settings中去。因此最终这些settings.py将合成一个,你可以在代码中导入setting。(不过对于子settings.py的处理我还在考虑是否要使用exec来处理,这样,子settings.py将不再是通过导入了,它们将在主settings.py的环境下运行,这样更象是在同一个环境下运行的。不过这块还没有想好。)
  2. expose的处理方式进行了扩充。在张沈鹏的留言中他建议能否自动映射,我理解可能有两种方式:一种是不需要expose,view函数直接映射为url,那么一方面用户无法控制哪些是可以访问,哪些是内部函数,所以我认为不使用expose不太好。当然expose只是一种实现方式,也许以后url的映射的定义会有根它的方式。另一种理解可以是只使用expose,那么当没有参数时使用自动映射。如何映射呢?我现在的方法是将view函数映射为:/appname/viewfuncname/arg1/arg2。这种方式接近web2py的,不过我没有controller一层,所以没有controller的url。那么它是怎么做的?后面会有介绍
  3. view函数的变化。原来view函数需要使用def func(req, arg1, arg2,…):,现在你不再需要req这个参数了。也就是你可以象web2py一样来定义view函数:def func(arg1, arg2):。但是你仍然可以在view函数中直接使用象request, response这样的对象,为什么,后面会有介绍。

expose的自动映射

你可以直接使用@expose来直接映射一个view方法,我是怎么做的?

def expose(rule=None, **kw):
    if callable(rule):
        f = rule
        import inspect
        args = inspect.getargspec(f)[0]
        if args :
            args = ['<%s>' % x for x in args]
        appname = f.__module__.split(‘.’)[1]
        rule = ‘/’ + ‘/’.join([appname, f.__name__] + args)
        kw['endpoint'] = f.__module__ + ‘.’ + f.__name__
        url_map.add(Rule(rule, **kw))
        return f
       
    def decorate(f):
        kw['endpoint'] = f.__module__ + ‘.’ + f.__name__
        url_map.add(Rule(rule, **kw))
        return f
    return decorate

当你使用expose时,rule参数将是function对象,因此,判断出rule是函数对象时,它将根据function本身的信息来得到它所在的模块(f.__module__)和函数名(f.__name__)。只不过f.__module__得到的是类似于apps.App.views的形式,因此要处理一下才能得到App的名字。同时一个view函数可以定义了参数,因此我还使用了inspect模块来得到定义的参数名。详情可以看它的文档,同时做一些试验。因此一个view函数会被自动映射为:/Appname/view_func_name/arg1/arg2的形式。

View函数的变化

原来view函数要定义为def func(req, arg1,…),现在你不需要第一个req的参数了。但是你仍然可以在函数内部使用request, response等对象。(至于在view函数中还能使用哪些变量我还要考虑中,可能会不断增加,这样非常接近于web2py的效果。)那么是如何实现的呢?原来我发现你可以动态修改一个函数对象的func_globals对象,如:

>>> def f():
…     print response

如果你定义上面的函数,编译不会出错,但是运行会出错。因为我们没有定义response。一种方法是定义全局的response变量,另外就是可以修改func_globals增加这个变量。如:

>>> f.func_globals['response'] = ‘hello’
>>> f()
‘hello’

可以看到执行没有问题。相当于我们定义了全局的response变量。这就相当于变量的注入,你可以直接使用。

2008年05月16日

昨天基本上已经有一个雏型放到svn中去的,如果你下载最新的代码已经是一个可以运行的版本了。目前因为只是在开发阶段,所以许多东西并不定型,很多东西可能会变化,因此你目前只能玩一玩。下面举些简单的例子,这些例子已经在svn中的。

1. 下载源码

svn co http://mymisc.googlecode.com/svn/trunk/kuaiboo

BTW,为什么叫Kuaiboo,因为我实在不擅长起名字,这个名字中英文混合,有些接近“快步”的意思,因此中文名字希望是开发web象快走一样方便(当然只是一个愿望)。当然如果你有好的名字可以贡献给我的话我会非常感谢。

2. 现在已经自带一个开发服务器,它是使用Werkzeug的,并且这个开发服务器自带reload功能,如果你做了任何怎改,它会自动装入,很方便,与django, GAE的差不多。在windows下的话,按Ctrl+C可以关闭。GAE的好象不行。不过按Ctrl+Break应该是都可以的。一旦你的程序出现语法错误,那么这个开发服务器有可能编译出错而退出,所以你要注意检查。这块回头看一看能不能改一下,不让它自动退出。

下载下来后,你的目录应该看上去象这样:

kuaiboo\
    apps\
        __init__.py
        Hello\
            __init__.py
            views.py
            templates\
            static\
    kuaiboo\

apps中将用来放置你的app的代码。要记住kuaiboo是象django一样以app为单位的。固定放在apps下。它是一个python的package,目前命令行工具还没有开发可以自动生成这种目录结构,不过很简单。

kuaiboo是库文件,放置各种各样的模块,现在有Werkzeug, webob,还有其它的一些东西,比如web2py的模板,我写的Form等。

在apps中已经有一个Hello的应用,它是一个测试程序,很简单。每个app都是一个package,因此有__init__.py。目前Hello中还没有数据库的处理,因此没有models模块。不过关于数据库这块我想不要绑得过死。比如GAE数据库与一般的关系数据库就不相同,因此这个框架可能更多的是在非数据库的地方吧,不过还没有想好。

views.py是放view代码的。templates是放模板的。而static是放静态文件的,不过目前还没有用到。为什么要static呢?这是我曾经在django中的想法的一个实现。一个app应该是功能完整的集合,所以静态文件也算其中之一,放在app中是为了方便复用,如拷贝。

OK。结构已经介绍完毕,下面开始写views了。

4. 第一个模板的例子

from frameworks.SimpleFrame import expose

@expose(‘/’)
def index():
    return {}

把上面的代码加到views.py中。让我一行行地解释。

from frameworks.SimpleFrame import expose 这里从frameworkds.SimpleFrame中导出expose将用于url的生成。在SimpleFrame中引入了一些常用的方法或对象可以直接使用。后面还会用到如url_for, redirect等。

@expose(‘/’) 这是一个decorator,它用来将下面的函数与某个URL相对应,这里是’/'。因此当你访问/时,就会调用index()函数。这里url的定义我是使用Werkzeug的,因此更详细的可以看它的文档。这种URL的映射可以支持参数定义,如’/blog/<int:year>/</int:month>/</int:day>,怎么样,再来一个’/user/<username>’,可以看到你可以使用<type:name>来定义或<name>来定义参数,其中type为类型。是不是比django的纯正则要简单?这个例子还没有使用参数例子。目前kuaiboo还不需要urls.py这样的东西,它会自动导入所有views函数,因此只要在你想要输出的函数前加上@expose就可以输出为一个可访问的view函数,没有这个修饰的将不会被访问到。这是一种分散方式url定义,在未来如果view文件非常多不知道会对性能有多大影响,因此以后还会实现一种集中方式的定义。

def index(): 这里定义了index函数,它目前接受一个req的参数(原来是需要req参数,但是现在已经不需要的,你可以在view函数中直接使用request, response对象,为什么?在另一篇Blog中我会仔细描述。)所以有view函数的第一个参数都是req。不过view是使用函数还是class好在我昨天的blog中也说了,不好选择,先用函数吧,至少decorator用着比较方便。这里req其实是webob的Request对象,因此详细信息要查看webob的Request文档。写到这真是有些象turbogears了,都是大杂烩,文档也都在别人哪里。看来用是一回事,写是另外一回事啊。

return {} 在kuaiboo中一个view可以返回三种东西:

  1. 字典,这样kuaiboo会自动查找对应的模板进行处理。目前kuaiboo的策略就是在所有app的templates目录下查找与函数名相匹配的模板文件,如index对应的模板文件名为index.html。因此要注意,如果你的app有重名的函数,在查找模板时可能会使用其它的app中的模板。不过kuaiboo在查找时会优先查找当前app的templates目录,因此一般你不需要担心。不过建议view函数名最好不一样。想一想如果不采用app的开发方式,将所有的view方法放在一起的话,它们会重名吗?不过我也在考虑是否可以自定义其它的模板,不过目前还不支持,有待于以后有需求或有机会去实现它。
  2. 字符串,可以是unicode。它将自动使用Response来封装。
  3. Response对象。使用它可以处理附件下件,cookie之类的设置。

因此上面的例子不是最简单的,因为我还没有定义一个模板。不过如果你把return {}改为return ‘Hello,kuaiboo’,你就已经可以测试了。先让我们把这个例子做完。

5. 进入Hello/templates目录,然后创建一个index.html文件,内容如下:

<html>
<head>
<title>Index Test</title>
</head>
<body>
<h1>Kuaiboo Framework</h1>
<p>This is a test page index.</p>
</body>
</html>

6. 好,下面就可以测试了。进入kuaiboo目录,进入命令行,执行:

python manage.py.py runserver或 manage.py runserver

7. 在浏览器输入: http://localhost:8000

看到结果了吗?