limodou的学习生活
百度空间 | 百度首页 
 
文章列表
 
2009-11-24 10:27

本来是懒得发布,因为最新更新也不是很多,不过从3.9发布到现在竟然也有1年多了,3.9发布还是在08年4月份,想不到时间过得真快啊。

Links

 
2009-11-12 21:33

stdyun是张沈鹏同学做的主机系统,在开始我申请了他提供了免费试用帐号,主要是想试一下Uliweb的部署。在使用过程中由于开始不太熟悉,获得了张教主的帮助,成功将uliwebproject部署成功,目前可以通过 uliweb.com.cn来访问(由于是试用期,因此可能随时关闭)。这个主机系统创建不久,目前已经开始可以租用,速度真是很快,提供ssh,mysql。下面是我将Uliweb的部署写出来,为Uliweb感兴趣的人提供一个部署的实例。所有尝试以svn中的最新版本为准。

在stdyun上部署Uliweb还算方便。

准备工作

因为stdyun不提供缺省的二级域名,因此需要用户自行去注册一个域名并进行绑定。具体如何申请和绑定
张教主在我的问题中给了很好的回答,可以参考:

http://groups.google.com/group/python-cn/browse_thread/thread/3b00351b97b6690a/bb28c5ec135d1b7b

stdyun环境介绍

一旦你申请帐号成功,stdyun会发送给你有关ssh,mysql的信息,因此你可以使用putty进行登录。具体登录过程不再说明。

stdyun已经安装好了一些环境,比如virtualenv,setuptools, easy_install。并且它所提供的python是最新的2.6.4。你可以认为在你的目录下已经有了基础的python环境了。

virtualenv是一个很方便在一个受限环境下创建一个完整的python的工具,由于stdyun已经安装好了因此你不再需要安装。并且它已经被激活,所以激活这步也不用执行了。直接使用就好了。

bin 目录是存放一些命令,如python,virtualenv的命令行工作,easy_install等。如果你在virtualenv下安装python模块,那么当存在scripts需要安装时,会安装到这个目录下。

lib 用来放置python下的库。安装的python库源文件就放在这个目录下。

Uliweb软件安装

因为你已经有了一个完全由你控制的python 2.6的环境(Uliweb可以运行在2.6下),因此你可以按照Uliweb的安装说明进行操作,完全没有问题。这里我列出通过svn来安装的步骤,这样便于与Uliweb的svn保持同步。

为了方便,你可以在$HOME目录下创建一个src的目录,然后进入这个目录,再在这个目录下通过svn获得Uliweb的代码,如:

  1 
  2 
  3 
  4 
  5 
mkdir src
cd src
svn checkout http://uliweb.googlecode.com/svn/trunk/ uliweb
cd uliweb
python setup.py develop

这样就安装好Uliweb了。

创建Hello

让我们回到$HOME目录下

  1 
  2 
  3 
uliweb makeproject hello
cd hello
uliweb makeapp Hello
这时我们的Demo项目就建好了。

部署

stdyun是使用fastcgi模式。而Uliweb已经提供了这么一个文件,就在hello目录下。检查一下runcgi.fcgi它的执行权限是否是x。如果不是请修改:

  1 
chmod +x runcgi.fcgi
不过这步一般不需要做,在最新的Uliweb代码中,通过svn检出的话应该已经是可执行权限了。

然后要修改一下runcfi.fcgi,主要是第一行改为:

 1 
#!/home/vhost/s63/bin/python
这里s63是我的用户编号,你要改成你自已的编号。

修改完毕,然后就需要在stdyun的控制面板添加url与handler的对应关系。

绑定

进入: http://stdyun.com/vhost/my
在下面的绑定域名处添加你申请的域名,如demo.uliweb.com.cn,然后点击绑定域名。


输入后进入目录绑定界面。我们想通过 demo.uliweb.com.cn来访问hello项目。配置如下:


输入后点添加即可。

然后过一会再访问你的域名。如 http://demo.uliweb.com.cn 你会看到一个Hello, Uliweb的信息显示出来了。

 
2009-11-05 12:52

感谢张教主的帮助,不过现在还有一点点小问题,因为有些包还没装上。不过首页已经可以访问了。uliweb已经在张教主的stdyun上部署成功了。几点事项:

域名(我去的9host.cn申请的,. com.cn 只要3块钱,续费要50元)
有了域名要设置对应的IP(IP为:119.88.56.193),具体见张教主的说明(同时要注意修改9host的DNS时要使用IE浏览器。 )   

http://groups.google.com/group/python-cn/browse_thread/thread/3b00351b97b6690a#
然后runcgi.py需要将后缀改为.fcgi。 不过这个我要再更新一下uliweb。

回头我会写一个更详细的uliweb在stdyun上的部署说明。

声明,因为我使用的是免费试用,因此可能用的时间不会太长

 
2009-11-04 12:46

在经过对beaker中的session替换之后,我终于又把cache给替换掉了。完全是自个儿重写。一方面它可以象一个dict一样工作,同时可以通过put, get来调用。使用这两个函数的好处就是可以有更多的参数。目前这个类在uliweb/lib/weto/cache.py中。

创建cache

import weto.cache

cache = weto.cache.Cache()

这样可以创建一个cache。因为没有指定Cache类的初始化参数,因此会自动以file格式创建cache。如果需要指定其它的格式和参数,可以设置:

storage_type, options, expiry_time

这三个参数。storage是类型,目前只支持'file', 'dbm', 'database',分别对应三种不同的存储类型。

options则根据不同的类型有所区别,比如'file'类型需要传入'data_dir',用以指定cache保存的路径。而'database'则需要指明要使用的表名和数据库连接的一些信息。

expiry_time是指定缺省的超时时间。这是当你在put时没有指定超时时间时使用的,在调用put时可以单独设定。

cache.get(key)

这样的调用,如果key不存在,或超时则会引发一个异常抛出CacheKeyException异常。

如果不想引发异常,则可以:

cache.get(key, default)

其中default不能为None,这样当key不存在,则不会引发异常,返回default值。如果为None,则同get(key)的效果。

cache.put(key, value, expire=None)

这样可以设置一个cache。如果expire没有传入则使用缺省的超时时间。时间以秒为单位。

同时为了方便函数的封装,还提供了

cache.cache(key=None, expire=None)

这个decorator。例如:

@cache.cache(expire=15) 
def f(*args, **kwargs):

@cache.cache(key, expire=15) 
def f(*args, **kwargs):

这两种都是可以的,区别在于前一个没有key参数,那它将根据函数名和参数来生成一个key,而后面则是由用户主动指定了一个key。

在进行上进的改造之后,原来的beaker就删除了,这样uliweb中不再使用beaker了。同时对原uliweb.contrib.cache进行了修改,去掉了middle_cache.py,而采用让用户自行调用的机制。同时为了同app的配置功能相结合和方便用户使用,在uliweb/utils/cache.py中编写了一个get_cache()的函数,同时对Cache类的增加了page方法。

get_cache()可以自动从settings中找到相应的配置。目前主通过两个secion来控制的:

[CACHE]和[CACHE_STORAGE],前者用来控制cache的类型和超时时间。后者是用来针对每一种类型来设置与存储相关的配置信息。在调用get_cache()时,你还可以传入一些参数,它的原型是:

def get_cache(cache_setting_name='CACHE', cache_storage_setting_name='CACHE_STORAGE'):

即可以指明使用其它的配置名,这样就可以在你的settings.ini中存放不同的cache的配置,通过get_cache来使用不同的cache机制。

为什么要对Cache进行扩展,Cache.cache原来是针对函数本身和它的参数,但是这样对于view有一点问题。有些view可能通过QUERY_STRING来处理不同的传入参数,因此在url上它们不同,但是在view函数上是完全一样,因此这种只根据函数本身和参数是有问题的。因此扩展的page这个decorator使用了request.url值,它是一个完整的访问路径,包括了QUERY_STRING信息。因此为了生成静态cache,可以使用改造后的Cache类。当你调用get_cache()时返回的cache对象已经是使用了这个新的Cache类了。

所以为了方便和更适合在Uliweb环境下使用,可以使用uliweb.utils.cache的get_cache()函数。例如:

  1 
2
3
4
5
6
from uliweb.utils.cache import get_cache()
cache = get_cache() #使用缺省的settings.ini设置。因此需要加入uliweb.contrib.cache这个app
@cache.cache(expire=15)
@expose('/index')
def index():
return {}

现在我把uliwebproject也添加了cache的支持,不过发现的问题是,不能简单的使用@cache.page()来对view方法进行处理。原因是:

在view方法中有对cookie的处理,采用cache的方式会屏蔽掉这块处理

因此在uliwebproject中并不是使用的decorator的方式,而是在view中对可以cache化的部分进行了手工处理,如:

  1 
2
3
4
5
6
7
8
9
10
11
12
cache = get_cache()
@cache.cache(_f)
def f():
content = file(_f).read()
if render:
content = to_html(template(content, env=application.get_view_env()))
else:
content = to_html(content)
return application.template('show_document.html', locals())

response.write(f())
return response
完全是手工来处理了。
 
2009-11-02 22:16

性能与功能的确有些矛盾。因为开发uliweb更多是从功能上考虑,因此在性能上我一直没有太仔细测试和分析过。最近找了一个主机部署了一下,别人告诉我刷新一下CPU占用很高,于是我想有机会的确还是要好好搞一下。于是加了一些跟踪,发现了一些问题:

1. get_apps() 的问题

因为uliweb是采用app方式来组织,而且app是允许使用python的包形式。在启动时,为了查找app下的settings.ini和config.ini等信息,使用的是pkgresource的resource_filename,它是要导入才可以的。但是一个导入可能会使得加载变慢。这块的确有些问题。为了查找包的目录,因此要导入,但是后面的处理未必会使用这个包,显得有些浪费。因此我修改了这块处理。如果包是由a.b.c这样形式构成的,我会只导入a,后面两个直接根据a的目录生成一个路径。这样只要保证a的__init__.py中没有太多的耗时的代码就可以了。这样优化后减少了一些时间。

2. pytz的问题

因为uliweb的ORM会处理时区的问题,而且我写了一个utils/date.py模块专门来处理时区转换。因此在启动时,为了省事,我自动导入了date.py模块,它会自动导入pytz模块。但是我发现pytz的导入非常慢。这样造成整个uliweb的启动变慢。因此这块我直接去掉了,让用户自已来处理好了。

3. 可能会引起问题的地方。app的__init__.py文件。因为考虑有些bind的代码会写在__init__.py中,因此在启动app时会自动导入所有app。因此如果有app在这里写了很耗时的代码会影响整个uliweb的启动速度。也许你会认为不好,不过uliweb已经提供了许多静态化的方法,如:bind和expose可以静态化,即在settings.ini中进行配置,这样__init__.py中可以是空的。

这里的问题主要是由于方便性考虑产生的:采用自动化的方式,减少用户的导入或初始化的工作,结果使得处理范围扩大化,影响启动效率。

注意我说的主要是启动时的效率,一旦启动不退出,效率要好一些。

因此uliweb如果每次都是重新启动必然会造成性能下降,比较好的方式还是驻留式,不要每次启动。象mod_wsgi, fastcgi应该是可以支持的。是不是自带一个web server采用反向代理会更好呢?象java一样。

 
2009-10-18 21:32

今天开发了一个新的uliwiki的项目,不错是今天,我是照着 http://code.google.com/p/django-wikiapp/ 这个项目来做的,不过象界面,象处理许多都是重写的.因为原来的项目功能挺多,我目前还实现不了,比如:comment, tagging, notification, feed等.目前只是实现了一个基本的wiki的功能,用户认证还没有.但是wiki的功能基本上都全了:

比如生成WikiWord链接,同时支持象[wiki:name message]的wikiword方式.

使用reStructuredText格式(目前只支持这一种)

编辑,删除,版本管理,恢复旧版本,查看旧版本.

其中版本管理我做得比较简单,我是每次保留全部内容,而不是增量内容,主要是为了方便生成版本差异.而django-wikiapp是保存的增量内容,因此处理上要复杂一些.

同时通过研究django-wikiapp发现了  http://code.google.com/p/google-diff-match-patch/ 这个好东西,可以用来生成比较后的结果,并且还可以生成patch.

下面上几张图,看下效果:

这是进入的首页面.

这是某个页面的编辑页面

这是版本信息,先选中不同的版本,然后点上面的Compare按钮可以显示下面的比较结果.

这是使用了google-diff-match-patch显示的结果,还不错.

现在uliwiki的地址在  http://code.google.com/p/uliwiki/  有兴趣可以试试和完善它.

 
2009-10-18 10:41

原文: http://j-lite.net/blog/2009/10/17/i-have-a-dream

以下是我的回复:

我也不是为了争uliweb要比django强大,我也说了uliweb有自已的优势,而且我认为比django强的,但django也有它的优势。而且我也在邮件列表中多次声明,每个框架代表一种哲学,不同的哲学引来不同的用户,所以我离开django也可以说是我的哲学与django的哲学区别越来越多造成的。

至于造轮的问题,因此我还是建议你有时间多了解一下uliweb。在今年9.5日的大会上我列举了自已创建的轮子的例子,比如:

整个核心的处理完全是自已写的,它是一个框架的灵魂,负责整个框架的启动,组件管理(app管理),配置管理,request和response处理,middleware的处理,这是每个框架不同于其它框架的核心,是无法复制的。如果只是简单的复制,那么这个框架存在的意义就没有了。其中整个app的详细支持是借鉴了django的思路,但是由我完善的。还有象view的处理,借鉴了web2py的思路,但是自已实现的。详细代码可以见uliweb.core.SimpleFrame.py.

还有许多的模块是我自已写的:

1. web2py的模板,已经被我改造增加了象编译文件目录支持,自定义tag支持,block的支持,这些都是原模板没有了,已经是uliweb化的组件了。
2.dispatch模块,完全是自已写的,实现类似于django signal的功能。但是整个实现是从ulipad发展来的,没有照搬任何人的东西。
3.i18n也是自已写的,是从ulipad发展来的。
4.weto是在我发现beaker这个session库有问题之后重写的,完全是uliweb的东西。
5.contrib下的所有组件都是我自已写的。
6.pyini完全是自已构思创造出来的,用于处理uliweb的配置文件。
7.orm这块是从头一点点构建的,也是一个框架很重要的部分。
8.form库也是自已一点点写的。
9.url映射的处理机制是使用了werkzeug的route为基础实现的,但是只是使用了它的基本功能,主要功能是uliweb实现的。

一个框架主要完成的功能其实不外乎:url处理,request, response,view,orm,组件管理,配置管理,提供一些实用的扩展。因此,你可以看到,从架构设计,从组件的实现,许多方面都有uliweb自已的实现,甚至完全是uliweb自已的实现。因此从web2py,从django,从werkzeug,从sqlalchemy更多不是简单的引用,而是思想的借鉴,是更多的封装。

所以,许多东西并不是简单了解就好象明白的。这是我想要澄清的地方。别人不认可uliweb没关系,很正常。但是我只是希望,评论一个东西首先要对它多少深入地了解一下,哪怕与作者交流一下也好,而是不看些表面。不仅从合理客观的角度来谈论一件事,更是不会误导别人。所以uliweb绝不是简单地组装出来的一个东西,它有自已特性甚至独一无二的东西。许多人一谈uliweb,就是从重装造轮的角度,但是他们并不了解许多uliweb上的设计的东西,也基本上没有在技术细节上的讨论,谈得很泛泛。这样对谁都不是公平的。

你所说的框架其实目前pylons和tg都差不多,而uliweb也是可以,django也是可以,只不过pylons和tg可能从组件上可以直接选择,而uliweb,django是可以自已定制开发,不能直接使用。而且你所说的更接近于某些人更偏重于自已去建,比如这篇文章:

http://pythonpaste.org/webob/do-it-yourself.html

自已建是没有问题。因此框架更多是给那些不希望,甚至不能够自已来做这件事的人准备的。但是自已建,可能需要了解的东西更多,正如我在构建uliweb过程中,我学到了比以前简单使用框架更多的东西,我甚至做了许多以前不知道自已还可以做的事情。各有各的乐趣。

 
2009-10-17 11:09
根据邮件列表中的回复加工

1. 提出问题:

使用webob在处理通过fancyupload上传的文件,发现会系统挂起,但只要先把request.body读出来就没有问题。因此在uliweb中,将原来使用的webob去除,改成了werkzeug来处理了。

2. qiangninghong的试验:

因为limodou反应的这个问题认为是cgi模块有bug导致的,所以很重要。今天晚上稍稍有点时间,写了一个测试程序来验证一下,但是发现似乎没有这样的情况?

测试代码在这里 http://code.google.com/p/hongqnlib/source/browse/

就是照着 FancyUpload 的 Attach File demo 页面 ( http://digitarald.de/project/fancyupload/3-0/showcase/attach-a-file/ ) 翻译了一下。运行 server.py 后,访问 http://localhost:5002/ ,上传了几个文件,都没有出现挂住的情况啊?

难道是我的这个测试有什么问题?请 limodou 帮忙看看。

3. 我的试验:

我把你的程序改了一下:

  1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import os
import mimetypes
import time
import socket
from hashlib import md5
import simplejson as json
import webob, webob.exc
from paste.urlparser import StaticURLParser
from paste.cascade import Cascade
import logging
from paste import fileapp


def app(environ, start_response):
request = webob.Request(environ)
if request.method == 'GET':
filename = request.path_info.lstrip('/')
response = fileapp.FileApp(filename)
else:
# logging.error( repr(request.body))
filedata = request.POST['Filedata']
r = dict(status='1', name=filedata.filename)
text = filedata.file.read()
r['hash'] = md5(text).hexdigest()
if request.params.get('response') == 'xml':
response = webob.Response(content_type='text/xml')
print >>response.body_file, '<response>'
for k, v in r.items():
print >>response.body_file, \
"<%(k)s><![CDATA[%(v)s]]></%(k)s>" % locals()
print >>response.body_file, '</response>'
else:
response = webob.Response(content_type='application/json',
body=json.dumps(r))
return response(environ, start_response)

#static_app = StaticURLParser('/static')
#app = Cascade([static_app, app], (404, 405))

if __name__ == '__main__':
from wsgiref.simple_server import make_server
server = make_server('localhost', 5002, app)
server.serve_forever()
分析如下:

1. 使用你的程序的确没有问题,使用我改的程序就有问题
2. 两个差别在于你在调用处理前使用了一个StaticURLParser,而我改后的程序是不使用它,在app中自已处理。这样的目的并不是使用StaticURLParser不行,而是这样的做法其实是在app处理前多了一层处理,那么这层处理会影响后面的处理,掩盖问题的发生。
3. 在我的例子中,只要把#        logging.error( repr(request.body))这行的注释去了,程序就正常。
4. 原因就是,只要你想办法在执行request.POST['Filedata']之前执行了象request.body之类的代码,这样会引起对body的整个读取,这时读取是按Content-Length来处理的,并且会放在缓冲区中,因此后续的处理就是从这个缓冲区来的了,因此缓冲区最后有没有回车换行是没有关系的。而使用flash控件上传文件,文件体示例如下:

ERROR:root:'------------ei4GI3ei4Ef1Ef1GI3ei4Ij5GI3GI3\r\nContent-Disposition:
form-data; name="Filename"\r\n\r\na.c\r\n------------ei4GI3ei4Ef1Ef1GI3ei4Ij5GI3G
I3\r\nContent-Disposition: form-data; name="Filedata";
filename="a.c"\r\nContent-Type:
application/octet-stream\r\n\r\n#include
<stdio.h>\r\n\r\n------------ei4
GI3ei4Ef1Ef1GI3ei4Ij5GI3GI3\r\nContent-Disposition: form-data;
name="Upload"\r\n\r\nSubmit
Query\r\n------------ei4GI3ei4Ef1Ef1GI3ei4Ij5GI3GI3--'

可以看到,最后是没有\r\n的。这不是浏览器的问题,是flash组件本身的问题,相关的flash的类本身的问题。但其实也不算一个问题,因为cgi的处理是基于multipart的boundary需要以\r\n结束这个假设,但这种假设在某些情况下有问题。相应的cgi的代码如下(从cgi.py中找到的703行):

  1 
2
3
4
5
6
7
8
def read_lines_to_eof(self):
"""Internal: read lines until EOF."""
while 1:
line = self.fp.readline(1<<16)
if not line:
self.done = -1
break
self.__write(line)
就是这个readline造成的,如果没有\r\n它根本不会返回。

因此前面的问题就是,如果不先执行request.body,则后面的request.POST['Filedata']会从流中进行读取,而不是缓冲区中,但flash正好又不返回\r\n,因此server在使用readline就停处了,造成挂起,进而引发浏览器的flash控件的超时。

而你的例子使用了StaticURLParser,可能会进行request.body的读取,所以掩盖了这个问题。当然它到底怎么做的,我没有继续深究。因此我改了你的程序,就是为了不让其它的因素干扰,问题就暴露出来了。
 
2009-10-15 21:38
最近一段时间一直在忙着ORM的优化,其中有几点:

1.增加__table_args__的配置。它和__tablename__一样是定义在Model类中的,可以用来增加在执行Table时添加新的一些参数,如果你使用mysql,可以如下定义:

  1 
2
class Todo(Model):
__table_args__ = dict( mysql_engine='InnoDB', mysql_charset='utf8')
这样将在建表时,向Table中添加这样的信息。上面的代码将以InnoDB和utf8编码来创建todo表。

2.增加OnInit类方法的调用。这个方法是交给用户来定义的,可以用来执行在执行完Table之后的一些初始化操作,它将在建表之前。比如:

  1 
2
3
@classmethod
def OnInit(cls):
Index('my_indx', cls.c.title, cls.c.owner, unique=True)
这样将创建以title, owner的索引,并且索引不允许重复。目前只支持索引的创建。对于简单的索引,是可以在定义Field时直接设置index=True来创建的,并不需要这种方式。这种方式可以认为就是为了创建多个字段的联合索引。

3.考虑缺省order_by的实现。但是想用户完全可以在Model中定义相应的方法来实现,类似于django的Manager的东西,比如:

  1 
2
3
4
class Todo(Model):
@classmethod
def files(cls):
return cls.all().order_by(cls.c.title.desc())
然后在使用时可以通过Todo.files()来返回按title降序排列的结果。所以使用这种方法倒是不一定要支持缺省order_by的配置项。不过有这个配置项的好处就是当需要实现通用的查询时,它可以自动生效。不过也可以考虑把结果集当成一个参数传给配置功能,总之还是有方法。

4.最重要的一个特性。增加表的注册,并且注册的表不一定是一个Model,而是一个模块名的形式,如以下两种都是正确的注册方式:

  1 
2
set_model(Model, tablename='user')
set_model('uliweb.contrib.auth.models.User', tablename='user')
这样注册之后,你就可以通过使用真正的表名来得到对应的Model类对象了。通过:

  1 
User = get_model('user')
这种方式首先可以使用在关系的定义中,如:

  1 
2
Reference('user')
ManyToMany('user')
对于关系定义,它可以根据表名自动导入对应的Model。而对于在程序中想直接使用某个Model,则可以通过get_model()来获取。

但是这种get_model()的方式要依赖于set_model()的注册过程。注册有几种方式:

1. 在导入Model文件时,随着Model的class的创建自动会调用set_model()来注册,因此只要正常导入相应的模块,就可以使用get_model()方法了。这种情况下,对通常的开发没有什么影响,用户甚至不必使用这种方式。

2. 由框架来注入。也就是uliweb来实现。这种方式首先要求将Model信息写入到settings.ini中,比如:

  1 
2
[MODELS]
user = 'uliweb.contrib.auth.models.User'
这样当uliweb在启动时可以自动采集注册信息。然后在orm这个app的__init__.py中执行真正的注册工作,通过调用set_model()方法。这时,注册的就不是Model了,而是字符串形式的信息。

然后在某个地方,如views.py中使用get_model()或导入models.py时,就可以自动生效了。

你可能会问,这有什么用呢?一般不都是直接导入来使用吗?完全够用了。

的确,一般的程序的确是根本用不上。但是Uliweb是一个框架,它要考虑代码的复用和替换的问题。考虑一下,在你的models.py可能需要对User表进行处理,那么你会去导入它。但是有可能这个User表不适合你的应用了,你怎么办?并且这个User表不是你自已写的,而是框架或别人提供的,别人可能还要依赖于这个表。因此简单的直接修改并不一定是好办法,因为它可能不受你的控制。重新写一个可能是好办法,但是因为直接导入的原因,比如你是通过:
from uliweb.contrib.auth.models import User
这可是直接hard code了,所以重新写必然还要修改导入的代码。那么要解决这个问题,可以采用的一种办法就是将外部依赖的内容配置化,和java中的注入依赖有些象。也就是我在定义自已的东西时,可能需要外部的东西,那么我并不直接导入,而是通过一种获取的方式来得到。这样工并不需要知道外部的组件的实际位置,这件事由框架来完成。因此uliweb现在实现的get_model就是为了实现这一配置化而设计的。

其实现在,象bind,expose都已经是可以配置化的了,都可以放在settings.ini中。如果完全配置化,将可以减少启动时的导入处理,并且替换会很容易。
 
2009-10-15 20:18

pyini.py是处理Uliweb的settings.ini的模块,今天向它添加了三个新的方法:set_var, get_var, del_var,它们的特点集中在第一个参数,它可以是'/'分开的字符串,如:'DEFAULT/flag',它相当于:

s = ini.add('DEFAULT') 
s['flag'] = True 

注意,它只支持一层的'/'切分,如:'DEFAULT/flag/name'相当于 'DEFAULT'和'flag/name'。

 
     
 
 
个人档案
 
   
 
文章分类
 
 
 
Uliweb(96)
 
Python(13)
 
Ulipad(12)
 
Web(3)
 
 
 
     
 
最新评论
 
文章评论|照片评论

 
 

很赞的空间,速度很快。
 
 

回复张沈鹏:改好了。谢谢。
 
     
 
好友最新文章
 
     
 
最近访客
 
 

jerrynlp

连看19集

yyobin

wbwylbt

登斯楼

心清以明

xrayaf

sowill
     
 
背景音乐
 
 
订阅我的空间
 
已有人次访问本空间
 
订阅RSS  什么是RSS?

您也想拥有这样的空间?请点此申请。
     


©2009 Baidu