2008年02月18日

Review Board 是一个使用Python + django 开发的代码复审工具,看上去不错。

2007年09月18日

I’v created a project db-dump on code.google.com, you can visit it at: http://code.google.com/p/db-dump/

And db_dump.py is used for dump and restore database of django. And it can also support some simple situations for Model changes, so it can also be used in importing data after the migration of Model.

So if you like it or want to try it, you can download it from http://db-dump.googlecode.com/files/db_dump2.1.zip

And if you have any idea about it just write a issue or send me an email, I’ll try my best to change it.

If you want to run it, just extract it to project directory, you should put it with the settings.py together, and run it according to the document of the project site.

2007年08月09日

前一阵实在太忙,对于Django的关注也少了许多。不过现在慢慢开始恢复。这不就有一件事情吸引了我。事情的起因是这个样子的:

一位叫Tom Tobin的朋友在 django 的邮件列表发表了一个建议,说希望把模板功能做成独立的模块。其实这个提议老早就已经出现了,只不过没有象这次讨论得比较激烈。邮件线索可以访问这里

对这件事的看法分为两派,很正常。一派以Malcolm Tredinnick 为首的,他们认为template因为是django的一部分,所以最好还是与django在一起,不应该被分离出去。他们不喜欢象turbogears那样的由多个模块组成的形式。他们不希望维护两个版本,而且目前的模板通过django.conf.config()还是可以方便地被独立程序使用。

而象Tom Tobin的想法还是比较简单,就是希望能够单独使用。其实我个人是倾向于简单的方式,所以独立出来也无不可。如果是我的项目,有人建议我独立出来,而且我认为功能的确相对独立或希望有更多的人使用,也可能会独立出来,哪怕是维护两个版本。

不过作为Django的核心成员Adrian Holovaty首先提了一些问题,象不希望维护两套版本等,并且他可能更关心如何让模板模块更好用,是否一定要分出来倒是不一定。后来他指出:是不是只要不需要再进行配置settings就足够了。我认为如果能做到这一点,我就已经满意了。

但对于Tom Tobin好象并不满意。他的确是希望是独立的模块,而不是django的一个子模块。特别是他后面说到自已的许多意见被shut down,他已经厌烦了争论,还是自已一个人走下去的话,让我深有同感!

从这里我们可出不同的哲学思想的冲击。对于完美派或保守派更多的是考虑整体,使用工作最简化。对于自由派或激进派更多的是关心方便性和扩展性。我个人的理解,django有些过于保守,当然这也是他的项目控制得比严格的地方,而且核心成员的思想非常鲜明,也算是一大特色了吧。

所以我现在更多的是象Tom Tobin一样,我做我的,你做你的,你的好我就用,不好我按我的方式来,可能也是因为哲学上还是有不少差异而不得已而为之。不过一个项目本来就无法让所有人满意,只有它可以扩展就行了。

2007年07月18日

首先是在邮件列表是看到的,地址在这里。使用它基本上是需要写一个脚本,不过可能比较简单,在它的Help页面上有几个简单的例子,但是我不知道是不是还有更复杂的使用。在上面我可以看到字段改名,但是不知道是否可以修改如长度之类的属性。有兴趣的可以试一试。不过我会不会用倒也不一定,因为我感觉使用db_dump.py工具挺好的,一方面可以导出数据,另一方面可以对数据进行再加工,比起仅仅是直接修改表结构来说还是有一些优势的。当然也可能是已经有一个可以使用的工具就不再想去尝新了。

2007年06月15日

在Django中试验了简单的mako模板之后,运行是没有问题了,于是我想试一试中文如何处理,这一试才发现还有许多细节需要注意。在处理中文前建议先阅读一下mako文档中关于Unicode那部分。从这部分的内容我们可以了解到mako在模板内部全部使用unicode进行处理。涉及到模板处理的数据我想大概有三个地方:

  • 模板文件
  • 模板数据
  • 模板中运算结果

让我们一个个来看如何正确使用。

模板文件

mako有一种全局性的处理,那就是在TemplateLookup中使用input_encoding参数,它指明了每个模板文件的缺省编码。另外,针对每个模板文件,你可以为每个模板声明一个模板所用的编码,正象python中所用的格式,如:

## -*- coding: utf-8 -*-

要注意在mako中支持两种注释方式,一种是单行的,它使用两个’#'符,这与python不同。上面一行要象python源程序一样放在最前面。而mako采用与PEP-0263相同的判断方式,因此它其实是一个正则表达式,表达式为:

#.*coding[:=]\s*([-\w.]+).*\n

因此你可以使用简化的方式:##coding=utf-8或##coding:utf-8

一旦你在某个页面设置了这个编码声明,它将覆盖全局性的编码设置。

感觉这个还是挺方便的。

模板数据

模板数据是将要传入模板中的变量,它在调用时是通过关键字参数来传的,因此你可以使用一个字典,如:a,然后使用template.render(**a)来传递。如果有中文那么你需要转为unicode,如果不转,mako会自动使用unicode()来进行转换,因为没有指定编码类型,再加上缺省编码如果不手工修改的话是ascii,所以相当于mako会按ascii编码来转换字符串,这一定会出错的。因此你要自已进行转换。

模板中运算结果

在mako模板中是可以直接写程序,表达式,调用外部模板进行处理的,因此有可能得到的结果不是unicode。因此你需要对计算结果进行转换,如${‘中文’},这样在模板中调用了一个中文字符串,但这样会出错,要这样写:${u’中文’}。不过每个表达式都这样处理真是很麻烦,因此mako提供了在TemplateLookup或Template创建时的一个default_filters参数,你可以指定对于每个表达式计算后使用哪些过滤器进行处理,因此可以指定一个decode.utf_8之类的进行处理。而这个decode是mako预定义。不过mako的过滤器目前好象不支持参数。使用这个过滤器后,当信息返回本身为unicode,则不会有问题,当为非unicode时会自动按utf-8进行转换。

为了将上述处理简化,我修改了mako_django.py文件(在zipbook项目中可以找到),增加了以下的处理:

  1. 将TemplateLookup类中的一些参数做成settings.py中的选项,这样用户可以通过修改settings.py的选项来控制模板的处理。主要有:

    MAKO_FILESYSTEM_CHECKS 缺省值为settings.DEBUG,它主要用来控制是否自动监控文件的变化以重新生成模板的py模块。
    MAKO_OUTPUT_ENCODING 缺省值为settings.DEFAULT_CHARSET,它用来控制模板输出时的编码。因为在整个模板处理时,内部是unicode,因此需要一个编码来转成字节字符串。
    MAKO_INPUT_ENCODING 缺省值为settings.DEFAULT_CHARSET,它用来控制模板文件读取时使用的文件编码。
    MAKO_DEFAULT_FILTERS 缺省值为['decode.' + settings.DEFAULT_CHARSET.replace('-', '_')]。可以看到使用了settings.DEFAULT_CHARSET编码。后面的replace是为了把"utf-8"转为"utf_8",不然在mako处理中会出错。

  2. 在使用TemplateLookup时使用了上述的参数
  3. 在得到一个template后进行渲染时,对于传入模板的字典对象进行扫描,将所有的字符串值(包括list, tuple,dict中的字符串)都转为了unicode。

经过上述的处理,只要保证模板,返回值,字符串都是统一的编码,如使用utf-8,那么使用中文应该不会有什么问题。

2007年06月14日

最近看了看mako模板系统,感觉功能还是非常强大,虽然还没有怎么使用,但至少对于我这个 Python 程序员来说,不用去开发乱七八糟的tag,应该还是很方便的。Django 的tag其实也是一种简化的方式,但这种方式的编程并不轻松,象mako那样可以在模板中灵活定义函数,并且可以为其它的模板文件使用,从使得代码的重用性就非常强。于是我开始先研究一下如何在Django中使用mako好了。

记得以前黄毅写过这方面的东西,最初是在他的Blog上,后来他又整理了一下发布在了 djangosnippets.org 上了,在djangosnippets.org上还包括了geshi这个模板系统。不过我目前对于xml的模板系统没有什么兴趣,而且从测试上说mako是比geshi快的,所以先研究mako好了。

关于mako我不想说太多了大家自已去看吧。下面我先简单介绍一下由黄毅所做的工作。总的来说,黄毅的工作是将常用的几个与模板相关的函数进行了重定义,比如:select_template, get_template, render_to_response。在使用时你有可能需要定义三个参数在settings中,分别是:

MAKO_TEMPLATE_DIRS 它是用来存放模板路径的,正如TEMPLATE_DIRS的作用一样。如果没有缺省为make_templates。同时对于每一个app都会将它下面的make_templates子目录加到模板目录中去,如果存在的话。

MAKO_MODULE_DIR mako的文件型模板是可以编译成.py模块的,这个目录就是指明生成的.py文件将放在什么地方。如果没有指定,则生成的.py文件将放在与原模板相同的路径中去。

MAKO_MODULENAME_CALLABLE 这个是用来提供一个编译模板名生成的函数的。缺省的就是在模板名后面加.py就可以了。你可以写一个新的生成规则的函数来生成你想要的.py文件名。

在最简单的情况下,你不需要修改settings.py的配置。只要将你的模板放在每个app下的mako_templates下就可以了。然后将djangosnippets.org上的代码,一个是common.py一个是moko_django.py分别保存到一个目录下。然后在view中从mako_django.py中导入render_to_response()函数来使用就可以了。

了解了黄毅的mako处理方式,我做了一些改进:

common.py 没有动

mako_django.py 将 MAKO_TEMPLATE_DIRS 改为 TEMPLATE_DIRS,这样不用为mako单独使用新的目录了。同时将每个app下的mako_templates子目录的处理改为templates,这样和Django现在的方式一样。

因为没有单独的mako目录,如果你混合使用django和mako的模板这样从文件名上可能会有冲突。因此我希望通过扩展名来自动区分。这样我规定mako的扩展名为mko。为了方便处理,我写了一个新的render_template()函数(这个函数我定义在了common.py中了)。

render_template(request, template_path, extra_context)

这个函数会使用RequestContext来生成Context对象,这样就可以处理TEMPLATE_CONTEXT_PROCESSORS。同时它会根据模板的后缀来判断是何种模板类型。在缺省情况下.mko就是mako模板。为了方便扩展,你可以在settings中设置一个选项:

TEMPLATE_TYPES

它是一个字典。比如可以这样定义:

TEMPLATE_TYPES = {’.mko’:'mako’, ‘.mk’:'mako’}

可以看到一个后缀对应一种类型。而对类型的处理目前是写死在render_template中了,所以如果想通过这种后缀来判断模板类型的话,需要修改代码增加新的扩展。不过目录应该足够了。缺省情况下这个项可以不用定义。

所以以我的方式来运行的话,你需要:

common.py 包括render_template和app_dirs的处理(同黄毅的)。

mako_django.py 我修改过的版本。

除了继续使用原来的TEMPLATE_DIRS和templates外,另两个选项与黄毅的相同。

使用时要注意区分后缀。

上述我做的修改都在 zipbook 项目中可以找到,其中我还做了一个测试:

http://localhost:8000/zipbooks/mako/

2007年06月10日

这是我新开发的一个项目,你可以在 Google 上找到 ZipBook

这是一个有意思的项目。最新看网上的小说挺多,而且我希望有文本格式的格式下载,这样就可以在手机中看了。小说的下载方式挺多的,不过我想以自已的方式来下载和加工。原本想做成一个UliPad的插件,不过想一想做成个web也许更有意思,于是花了两天时间做了一个雏型。

它主要的功能就是让你输入一本小说的目录页面的URL,然后它就可以进行分析目录,然后自动下载每个章节。下载后会提取纯文本存到数据库中。在页面上你可以点击下载将整个小说以zip包的方式下载到本地,除了提供分章节的文本方式还提供将所有内容存到一个文本中的功能。

主要技术处理:

1. 页面分析

不同的站网,结构,内容编排都是不同的。因此在项目中有一个plugins目录,它用来存放每个可以处理网站的解析模块。在plugins的__init__.py中定义了域名与可处理的模块名的关系。因此并不是所有的网站都支持的。对于一个不支持的网站你只要在plugins中写一个新的模块。这个模块需要提供三个方法:parse_title用来从目录页得到小说名,parse_page用来从内容页得到文本的内容,parse_index,得到目录的详细信息。有了这些信息,zipbook就可以自动下载了。首先是根据目录url下载得到小说名和目录结构,然后再通过多线程分别下载整个目录结构。

2. 生成Zip文件

使用我以前写的zfile.py模块,不过原模块不支持将字符串直接写入zip文件,于是做了下扩展。使用这个模块写zip文件比较简单。然后就是HttpResponse的处理,基本可以参照Django Step by Step中关于csv下载的处理。只要注意把mime类型和下载的文件名搞对就行了。其实可以使用mimetypes模块的guess_type来猜mime类型。

难度到是没有。但有一个比较麻烦的就是如果在一个请求中进行处理的话,处理时间很长,前端页面长时间就不动了。原来想通过Comet来实现,不过没有看到Django中如何做,所以就放弃了。后来想通过ajax去轮询,不过后台需要是异步处理,我想到的是写一个独立的守护,或通过后台执行,不过在windows下可能不方便就没有试,所以处理时间比较长。想实现进度显示碍于技术没有实现。

Todos:

1. 因为所有章节都已经有了,所以可以做一个显示的界面。现在是只能下载看,不能在web上看。

2. 因为考虑到是生成txt,所以不能处理有些电子书就是图片的情况。如果要支持,只能是生成html格式了。同时还要考虑图片与链接的关系。

3. 增加更多的站点的支持。

4. 没有做界面,很丑陋,需要弄得好看些。

5. 书的tag支持

update 2007/06/11

当前显示界面

2007年06月09日

看到的blog在这里。其中比较有意思的是:全部Ajax效果,使用了Mootools 和 JavaScript VectorGraphics 库,后台是使用Django。

这里是它的一个图:

我下了一盘,我的棋艺不高结果还嬴了。 :)

2007年05月31日

Many people know that Guido like django, that’s right! Today Google
Developer Day is held in Beijing, and Guido also made a Python
introduction. In his talk he said at least 4 times that he likes
Django. And I’m very excited about this. And I think maybe it’s a
great opportunity for Django development in China, and I hope more and
more people would like to learn Django from now.

2007年05月28日

今天看到 Russell 发的一个提议是关于实现用的newforms的widgets时如何处理Media的问题。这一点就目前django来说的确不是很方便。在以前我也写过关于在app中实现对于静态文件的支持,也是由于这一点。由于不象PHP那样以实际的目录来运行,django其实是在一种映射出来的url方式下来工作的,而且考虑到效率的问题,静态文件一般是不处理的。

在这个讨论中,Russell主要提议是对newform中要用到的css和js等静态文件进行处理。在我看来这只是静态文件中处理的一部分而已,最好是从完整的html页面来考虑,如何处理静态文件,如何在各个组件中方便地与页面进行集成。如果有一种通用的页面模式,并且各个组件可以方便将静态文件导入并在合适的位置进行生成才足够方便,但这样一来现有的模板就太简单,一种是重新设置新的模板处理,另一种是可以考虑通过js来动态插入静态链接,如css和js等。在django中的处理还主要是以静态html方式为主,但是我认为这只是最简单的一种,而且也不是很强大,对于复杂的处理则能力不足。应该多结合ajax技术进行。当然从web的整合处理来说,也许分成前端设计和后端设计更好。django目前已经包含了许多的前端设计,但是没有使用ajax毕竟不是很cool。

讨论中另一个问题就是有人提出不要引入过多的css之类的文件,而是需要进行自动合并,这是一个更加复杂的问题。

[讨论链接]