2006年03月29日

www.djangocn.org 就是我在 dreamhost 上申请的web 空间,woodlog 就是装在这个空间下的。现在它只有一个blog ,那么以后我会把我做的一些web的项目也放到这个空间上去。做 web 与其它的 GUI 不同,web需要一个展示的环境才更方便别人了解。

同时今天看到 django 的代码变化很大,据我的了解,增加了后台数据库对多线程的支持。我以前写的对于 Sqlite 多线程支持的 patch 没有用了。这个变化非常大。

另外对于url的生成也有所讨论,主要集中在两点:

1. 如何方便生成应用相关的URL,目前还没有好办法。在 woodlog 中我使用了自已的方式。

2. 对于  model 中提供 get_absolute_url() 方式进行讨论,结论是虽然不是最合适的地方,但却是方便的所在。

上一篇 Blog 讲了关于如何部署到 DreamHost 的事情,但有一点给忘了,那就是换到 MySql 之后汉字的事。在切换完后,我提交了一个贴子,有中文,但查看时都是问号。一直使用 Sqlite 没有处理过汉字的问题,看来不得不解决了。在 django  的邮件列表中查了查,提问的不多。主要就是在 mysql 4.1 以上的版本(DreamHost是5.0的)不仅数据库在创建时有编码的问题,客户端也有。一般来说支持多语言的需要在建库时指定 utf8 编码。但我的数据库是通过 DreamHost 面板来做的,我也不知道是什么编码。为了试验,我在我的机器上安装了 mysql 进行测试。但它好好的,一点问题都没有。因此在 django 的 ORM 中对于 mysql  的版本 >= 4.1 的都有一个 set names ‘utf8′ 的语句执行,这是自动的。因此已经保证客户端的编码正码。那么不正确的就是 mysql 的服务端了。

我在 mysql 的主页上查到可以通过 alter database 来指定数据库的编码,于是进入命令行,执行了一下,命令成功。但结果仍然是问题。再建一个新的贴子,也是一样。没办法,我进入命令行手工将数据库 drop 掉,然后重新创建。创建时指明了 utf8 参数。然后重新 syncdb 了一下数据库。再创建新贴子,成功了,汉字出来了。天知道通过 DreamHost 创建的数据库是什么编码的。对 mysql 不熟,也不知道如何去查,反正能用就行了。

具体的 mysql 的文档

一边开发 woodlog 一边想让更多的人可以直接看到它的样子,并且对它进行测试。听说 DreamHost 有段时间了,但一直没有下定决心也整一个,因为总想找些现成的,特别是懒得配置。但为了方便自已调试和修改,我终于下定决心整了一个,而且参照网上的说明,输入一个优惠码的话,可以第一年便宜到 $24.4 ,这样合人民币 160 块左右,应该还算可以。毕竟我是为了测试软件,最终希望部署到别人那里去。

整个申请,部署的过程基本上还算顺利,从申请到部署成功大概有三四天左右吧。下面把整个过程记录下来。

1. 参考这篇 Blog DreamHost申请指南

这篇文档写得不错,很详细,而且给出了一个优惠码,很感谢。我就是用得它。我采用信用卡支付,我使用的是可以办理国际业务的信用卡。在申请之后, dreamhost 会自动创建你的用户,然后你可以上去看一看。但生效要转天,因为我是晚上办理的。同时还可以申请一个免费的域名,不错。我申请的叫: http://www.djangocn.org 。已经可以访问了。上面目前就是我做的 woodlog 系统,有兴趣的去看一看吧。

2. 到了第二天,收到了若干封 dreamhost 的信,再登录到dreamhost的控制界面中域名还无效,但象ftp用户什么的都已经生成好了。不过听人家说可以使用ssh登录,怎么没看到有说明啊,再等一等吧。

3. 到了第三天,说明域名可以使用了。访问了一个,果然,不过没有东西,只有一个目录列表。上面有我原来想安装的 wiki ,但我没有配置。于是进入 Manage Domains ,一旦它生效了,你就可以看到 web hosting那项有一个 Edit 可以使用。点击后,选中 Fastcgi 支持,这个很重要,部署 django 就靠它了。在这里你还可以设置你的 web 目录,回头放置文件要用。

这里你可以使用putty软件来试一试你的 ssh telnet 了。完全按 ftp 的配置即可。如果成功,说明功能基本开通了。

以前从来没有这样操作过,所以许多东西还不是很清楚,而且不完全熟悉 DreamHost 的系统都提供了哪些东西。既然开通了,下一步就是部署了。找到两篇文档:

TurboGearsOnDreamHost
DjangoOnDreamHost

这两篇都有一些用,但都不完全。先说一下我的要求:

  • 安装 Python 2.4, 因为有一些 decorator  用法
  • PIL要处理上传的头像
  • PySqlite2想使用sqlite3数据库,省事

在 Django那篇文档中没有如何使用 python 2.4 的说明,而 TurboGears 中有,还不错,于是按照说明开始操作。步骤和目录安装完全是一样的。在操作中感觉 DreamHost 还是挺快的,而且编译什么的都没有出错,挺好的。

PIL 因为是标准的  python 安装方式,因此到 PIL 的主页把链接一拷,使用 wget 下载。然后解包,执行 python setup.py install 即可。

看到有 mysql 包的安装,顺便也做了下。最后没想到,我改成了 mysql 数据库了,这是后话。

pysqlite2 也装了,使用 easy_install 。

然后再按 django 的文档使用 svn 从 magic-removal 中取得最新的代码,放在 django_src 目录下。接着设置一下 .bash_profile 文件,主要是路径什么的。

在 dreamhost 中我的目录是这样的:

/home/limodou 这是我的主目录
/home/limodou/djangocn.org 这是 web 目录
/home/limodou/lib 这是存放自已编译的东西的
/home/limodou/django_src django的最新M-R版本
/home/limodou/django_projects/woodlog woodlog 存放于 django_projects 目录下

安装 woodlog 很方便,因为它的代码在啄木鸟的 svn 中,因此使用 svn 就可以取过来。

基本环境装好,开始配置 Fastcgi 了。基本上按 django 文档进行的。

主要是先下载 fastcgi.py 放在 djangocn.org 目录下。然后编写 django.fcgi 和 hello.fcgi 。不过编好后访问 http://www.djangocn.org/hello.fcgi 出错,时间等待很长,然后是 500 的错。实在不知道怎么回事,django.fcgi也是如此。因为太晚了,就先睡觉了。

第4天。又看了TG那篇文档,才发现可以通过手工运行 hello.fcgi 来进行测试。于是乎登到主机上,来到 djangcn.org 目录下,执行 ./hello.fcgi 天,报错。再参照 TG 的文档,先修改了第一行为 #!/home/limodou/bin/python/bin/python 。还是报错。说是格式不对。然后我又发现拷贝的代码缩近不对,改正确的,然后又在 ‘Hello, world!\n’ 后面又加了一个 ‘\n’ ,终于成功了。

于是同理处理 django.fcgi 。而且在页面中已经可以访问了,不过出现的是调试出错的页面。不管怎么样,说明可以运行了。发现是pysqlite2报错,说是找不到数据库的配置,可是我明明配置了呀。进入shell 后手工导入: django.db.backends.sqlite.base 报错,说明 _sqlite.so 有一个函数不支持(具体错误信息记不清了)。后来去 google 上查了查,说是 pysqlite2与sqlite的版本不配匹。我很奇怪,难道 dreamhost 上装了 Sqlite 了。在命令行下执行 sqlite3 ,果然进入 sqlite> 了。看来是装了。于是我去 sqlite 的主页下载了最新的 3.3.4 源码然后编译。不过后来还在 dreamhost 上找到了关于 sqlite 编译的一些说明。编译是成功,但还是不行。于是我不想再试验 sqlite 了。全面改到 mysql 下去吧。于是修改 settings.py 的数据库配置。在改之前已经到 dreamhost 上的面板中生成了一个 blog 的库,用户名和口令也都有了。

但在访页面时还是报 sqlite3 的错误。看到django文档上有一个google的讨论和django的文档也都谈到可以使用pkill django.fcgi 来杀掉进程。试了试,说是有个表找不到。高兴,说明基本成功,就差执行syncdb 了。进入命令行,执行 python mange.py syncdb ,终于行了。再进入页面,内容出来了,但css找不到。

再参考 django 文档,看到有一些 rewrite 的配置说明,因为不熟悉,不知道加在哪里,后来查了查 google,原来就是要创建一个 .htaccess 文件,就在 djangocn.org 就行。然后加到里面就行。不过对于其中的规则不是很清楚。原本我还想怎么让访问 django.fcgi 时不是 http://www.djangocn.org/django.fcgi 的形式呢,这样多不方便啊。原来通过 rewrite 规则就可以做到,这下明白了。因为所有的css和图片都以 medias 开头,于是我照抄:

RewriteRule ^(media/.*)$ – [L]

增加一行:

RewriteRule ^medias/(.*)$ /home/limodou/django_projects/woodlog/media/$1 [L]

但是连访问都不行了。这个rewriterule到底做什么用呢?怎么使呢?查了不少的文档,终于明白了一件事,它是用来处理url映射的,不是用来象 Alias 一样提供别名的,我犯了一个错误。看到 django 文档上有一个处理是将admin的media目录链接到 djangocn.org 这样的目录下。我想我也需要这样做。于是:

ln -s  /home/limodou/django_projects/woodlog/media $HOME/djangocn.org/medias

这样再增加一个rewriterule就行了:

RewriteRule ^(medias/.*)$ – [L]

然后杀掉无用的 django.fcgi 和 python 进程(可以使用ps -A来看,还可以使用 kill -9 来杀),再试一试。终于OK了。

而且我发现使用 DreamHost 根本不需要考虑重启 server 的事,只要杀掉进程即可。而且总有一个 django.fcgi 在起着。杀了它又会出现一个新的。因此只有一个的话例也无所谓。

经过几天的折腾,woodlog 在线版终于可以使用了。

2006年03月27日

Theme可以译为主题,最简单的用法就是换肤了。在这里我希望实现 Blog 的自由选择模板。因此今天我主要是在 woodlog 上进行 Theme 的设计和对首页实现了更换 Theme 。当然我只是自已想出来的方法,可能通用性,或处理方法并不是很好,而且功能上也可能很弱,但目录已经可以满足我的要求了。下面我简单地介绍一下我的实现。

对于可以更新显示的内容,其实主要是CSS和一些图片,当然布局和内容也是可以换的。因此仔细考虑下来,主要包括模板,CSS和图片了。而图片可以与CSS放在一起考虑,主要的原因就是模板可以放在app自身的目录下,而CSS和图片因为是静态的,需要放在单独的media目录下。那么每个 theme 都需要有一个名字,它们的分配就是 themes/themename 。这样每个 themename 是一个子目录,对于模板目录和media目录都是一样的。

django 中由于对于模板和静态文件的处理方式不同,因此需要有两个配置。而对于 theme 本身一是我需要一个标志来指明是否使用 theme 功能,然后就是使用的 theme 名字。这样,对于模板和静态文件都可以先根据是否使用的标志来判断是否进行 theme 名字的处理,如果使用了 theme 功能,再找到当前使用的 theme 名字,生成最终的结果。

对于 theme 功能的设置是单建了一个 app,叫site,它可以管理是否使用 theme 功能和使用的 theme 的名字。而这个名字为了简单我放在了 settings.py 中作为一个 list 来管理的。这样 theme 的名字就从这个列表中选择了。

对于模板的 theme 处理主要分为:

  • view 代码中的使用
    主要集中在了对模板的选择上。为了方便,我在config app 中增加了对 theme 功能启用的判断和返回当前 theme 信息的函数,如果没有启动 theme 功能,则返回为空,也就是不使用theme的状态。因此,增加这些函数之后,不管使用还是不使用 theme 功能都可以正确处理,简化的代码的处理。比如,我经常要使用 render_to_response(templatename),为了支持 theme 我在 config 中增加了一个 theme_render_to_response 的函数,功能同 render_to_response 一样,只不过它会自动判断是否使用了 theme,并正确处理当前使用的 theme, 生成正确的名字。目前因为它只适合我对 theme 的处理,因此可能通用性不是很强,不过可以作为一个参考。对于 django 的模板在选择时还是有一个有意思的是,render_to_response 可以接受一个模板的列表,也就是可以是一系列的模板名,找到第一个可用的返回。这样就可以实现当生成的 theme 的模板名不存在时,则使用缺省的模板,可以大大简化 theme 的处理。它的意义就在于,如果一个 theme 对内容没有任何变化,那么对于模板来说,完全可以不用创建所以的模板,而还是使用原来的模板,那么剩下的工作只是对静态文件,如CSS, 图片进行处理即可。如果有内容的变化,只要对有变化的进行修改即可,非常方便。
  • 模板代码中的使用
    上面是讲了在 view 代码和对模板的处理上如何运用 theme 功能。在模板代码中还要对theme进行处理,主要是根据theme来使用正确的css和图片链接。但这里没有查找模板代码那样可以不存在时使用缺省的,静态图片因为可能通过 web server 来提供服务,所以得到的就是一个链接信息,因此不容易得到地址是否有效的信息,所以只能是一一对应了。因此如果一个CSS文件或图片文件需要通过theme来支持,为了得到正确的结果必要要提供相应的theme内容。为了在模板中使用theme功能,我在config中的templatetags中的config.py中增加了得到当前的theme,然后与链接进行拼接的custom tag功能。比如: {% theme_media_path "woodlog.css" %}" 。在使用前还要先 {% load config %}。

    但这样足够了吗?不完全。在view中可以通过config提供的theme选对功能得到一个可用的模板,如果theme模板不存在,则使用缺省模板。但在模板中还存在模板间的引用,如 extend 和 include 。因此为了让它们也可以支持 theme,我还创建了 theme_extend tag(include 还没有做),这样在使用 theme_extend 时,它的功能与 extend 一样,只不过,它会先找 theme 对应的模板是否存在,不存在则使用缺省模板。这样功能就完整了。

对于CSS和图片主要就是创建好与theme名对应的目录,然后去修改CSS和图片,本身不涉及到改动代码,因为对于它们的引用都在模板代码和View中就完成了。它们只是一个被引用的对象。

大家可能看到了,在前面我假定 theme 的目录结构为 themes/themename ,其中themename可以通过界面进行选择,但 themes 如何处理,是固定的吗?因此为了更通用,我还在 settings.py 中设置了两个值:

TEMPLATE_THEME_ROOT = ‘themes’
MEDIA_THEME_ROOT = ‘themes’

它们一个用于模板的引用,一个用于静态文件的引用,因此上目录结构可以改为:

TEMPLATE_THEME_ROOT/themename
MEDIA_THEME_ROOT/themename

完全可以由你来定义。当然,为了方便处理,我在config中增加了好几个函数来自动处理,如:

get_template_theme_root
get_media_theme_root
get_current_theme
join_app_path
theme_template

等,不同用途的 api 可以用来处理 theme。

上面讲得可能有些乱,大家看一看思路即可。现在的处理就是:

admin用户进入管理界面,然后进入站点的管理,在那里可以选择一个theme的名字。然后再进入主页,页面就变化了。很简单。

2006年03月26日

今天到的人还算不错,特别请来了阿北给我们做豆瓣网的介绍。张成也带来了不少同事,主要介绍爱发现网站的功能和简单的设计,这可是使用 django 开发的哦。我主要还是介绍了 woodlog 的功能和设计方面的一些东西。

在会议上大家就各方面内容进行了广泛的讨论,比如 woodlog 的性能,最大用户数,这些说实在的,我目前开发 woodlog 还是为了学习,许多并没有考虑。后面阿北在介绍豆瓣网的时候,更多的给我的感觉是对性能的要求。从技术上讲,功能本身可能不算什么,主要是性能。阿北的体会的集中在数据库,在硬盘上面。当初阿北选择 MySql 的主要原因就是对性能的要求,而且 MySql 从各方面来说使用人数众多,应该是一个可以接受的产品。其它为了加快性能如采用 memcache 来处理 cache 等。因此阿北说得有一点很重要。他为什么不使用 ORM ,因为 ORM 一是没有经过性能的测试,另外是 ORM 多了一层包装自然会有损失,而且许多数据库的优化调整将无法使用。这是事实。对于我来说,方便,功能是第一,而性能是第二。但对于阿北,对于商业应用,性能可能是第一的,因此也更直接。

当然并不是说要放弃 ORM 放弃 framework ,因为不同的应用对性能的要求不同,而我考虑是更多的是小型应用,对性能的要求不会太高。这也是不同的目的,出发点自然不同。

张成兄展示了他们使用 Django 开发的爱发现网站。这是一个类似于 Digg 的网站。用户可以提交他从任何地方看到的新闻,而且爱发现网站也提供一个 RSS 聚合功能,方便用户提交。用户提交后将进入待选区,需要别人的推荐,然后才可以进入首页。以前张成给我过一个网址,那时他说美工没有做呢,的确是文本一片。不过后来学过一些 CSS 设计的文章,的确新式的网站设计就应该是这样的。Html 输出的是结构化的内容,显示交给 CSS 来做。现在看上去就非常漂亮。

最后就啄木鸟的内容管理各抒己见,不过基本上是同意对分类再明确,再简化。我从一个写程序的角度出发,我更希望做一个内容管理系统,其它人则有些还是希望在 wiki 上改,意见不同。不过 Zoom.Quiet 到是表式可以同时做,那么如果有这么一个系统的话,希望可以用起来。

整个会课还是很成功,就是 Zoom.Quiet 照片照得差了点,可能是不太会用我的照机吧,有些模糊。本来是希望有一次“腐败”的,但没有准备好,只有算了。

具体的会课照片和录音可以访问啄木鸟wiki

2006年03月25日

一直有个想法,那就是将我写的 woodlog 放在啄木鸟主机上运行,但不知道效果会如何,只是想为啄木鸟尽一份力,所以我希望它能有些用。再加上在开发 woodlog 过程中的确学到了不少 web 开发和 django  开发的一些知识。不过,今天简单地对 woodlog 在本机上进行了测试。感觉在 windows 下使用 apache 的性能的确还是有些慢,而且如果页面的动态生成内容比较复杂的话,的确挺影响性能的,而且我还没有大量的数据进行测试,如果数据库一大了,影响会更多。下一步可能是要考虑使用 cache 的技术了。我甚至感觉 django 自带的 sever 性能都高于 Apache 呢,这还是在调试全开的情况下。先不管性能了,下面说一说功能的完善。

感觉到做为一个正式的产品要上线的话可能还有许多要考虑的,以前想得不是很多。最简单的,分页处理。数据一多了不可能都在一页就处理了,因此就需要分页处理。好在我写了一个分页处理类,用它还算方便。主要就是将以前没有太考虑的管理界面中也加入了分页,其它的页面是在开发时就加入了,但是今天在完善管理界面时才发现有些地方,如Blog的管理,评论的管理,成员的管理等没有分页功能,这不才加进去。另外就是相关数据的处理。我发现的主要是删除引发的问题。比如删除一个 Post ,那以我只是将 Entry 记录删除了,但想到还有相关的 tag, comment, category 等内容都要删除才行。还有就是如果我删除了一个用户,同时要删除他的相关的所有信息才行,因此又增加了这些处理。代码虽然不多,但是要想到,而且要全面才可以。

目前感觉不是很好的就是没有一个好的插件系统,相关的处理结合得比较紧密。因此要考虑如何设计一个方便的插件系统,哪怕象urls.py的方式也行。再有在浏览页面时,我会根据登录用户的信息生成一些相关的处理链接。如用户A在查看自已的blog时,woodlog会在每个blog生成一个编辑的链接,还会在每个评论上生成一个删除的链接,这样就不需要进入管理界面去做操作了,可以直接在浏览时操作,应该会比较方便。但一个问题就是,我点了链接,结果进入了原来管理功能在处理后跳转的地址,无法回到正在浏览的位置了。因此我想需要对HttpResponseRedirect作一个小小的封装,可以根据链接所带的QueryString来自动跳转回原来的链接,比如使用:

http://domain.com/setting/blog/edit/2?next=http://domain.com/blog/user/2006/03/25/2.html

这样在编辑完blog之后,可以根据next的值跳回到原来的位置上。这个处理应该不会太复杂,而且我想可能很实用。回头加上。

因为想着要在 Apache 上部署 woodlog ,因此做了一下移植的工作。所得并不多,的确有一些是bug。配置工作并不多,按教程上基本可行。主要就是路径改为绝对。在 woodlog 中增加了一个 setup_appache.py 用于apache的运行。那么在修改后一切都挺好,就是发现在运行时会出现:

Sqlite objects created in a thread can only be used in that same thread.

这样的错误,导致程序无法继续下去。查了查,在 django 中还没有人解决,不过有人提到过。在 Trac, CherryPy 中都出现过类似的错误。其实以前在使用 sqlite 作数据库的时候也出过。主要问题是由于多线程,据说是因为使用fcntl的 lock 机制,在多线程上有问题,因此不同的线程不能共享连接。因此以前就是通过每次都创建新的连接来解决的。

这些在 django 中也出现了问题,于是参照 http://code.djangoproject.com/ticket/900 的代码也作了一个补丁,我这里是不再报错了。补丁采用了一个线程字典来存储每个线程的连接,当连接不存在,或找不对应线程的连接时,就会创建新的连接。因此这样就保证了每个线程的连接不会共用。不过,没有自动释放的机制,会不会引发内存占用过大呢?还不清楚。

如果大家也出现了同样的问题,可以下载我提供的patch试一试。记住,第一个有问题,在使用第二个。

下载: http://code.djangoproject.com/attachment/ticket/1533/sqlitebase_02.patch

2006年03月23日

在研究完 django 的文件上传之后,我开始在 Woodlog 中加入头像管理的处理,但仍然发现问题。

1. 上传非图象文件不报错

校验的处理我的确做了,也加了调试信息,但是不报错,很奇怪。查来查去我终于明白了,一般校验的数据来自于 request.POST.copy() ,而上传的文件信息在 POST 中并不存在,而是在 FILES 中。因此,只对 POST 中数据进行校验是无用的,因此我作了一个合并处理的处理。如:

data = request.POST.copy()
data.update(request.FILES)

这样数据就全了,然后再校验就行了。不知道别人有没有遇到过这样的问题。

2. 如何限制图片的大小

在 django 的 wiki 中找了一个 Validate 函数:

def isValidSize(field_data, all_data):
    im = Image.open(StringIO.StringIO(field_data["content"]))
    if im.size[0] > 150 or im.size[1] > 150:
        raise validators.ValidationError, "The image size should be in 150 * 150"

在使用前需要导入:

from PIL import Image
import StringIO

这里限制图片尺寸不能超过 150*150 。使用 PIL 模块进行处理。

3. 生成缩略图

又从图上抄了一段代码改造了一下,程序在 utils/image.py 下:

def thumbnail(filename, size=(50, 50), thumbnail_filename=None):
    image = Image.open(filename)
    image = image.convert(‘RGB’)
    if image.size != size:
        image.thumbnail(size)

    # get the thumbnail data in memory.
    if not thumbnail_filename:
        thumbnail_filename = get_default_thumbnail_filename(filename)
    image.save(file(thumbnail_filename, ‘wb’), "JPEG")

    return thumbnail_filename

也不是很困难。这里还用到了在 image.py 中定义了一个 get_default_thumbnail_filename() 函数,它将对指定的文件名后缀改为 ‘xxx.thumb.jpg’ ,这是当你没有指定缩略图文件名的情况下。

4. 设定保存文件名

原来没有太注意,直接使用FILES对象中的 filename, 但这其实是上传的文件名。如果两个用户上传相同的图片就不太好。不过 django 发现有重名文件时,会自动在文件主名后面加’_',这样就不会重名了,但并不好看。因此在保存时还是由你来指定文件名最好。比如我根据用户名来生成图片的文件名。

这样在头像处理上,先由用户上传图片,然后校验通过后,先保存原始图片,并按用户名起名,然后生成缩略图。缩略图用在显示Bloger的信息和个人Blog上面。回头加一个开关项可以显示或不显示头像在Blog页面上。

在我写的教程中的第八讲就有关于通讯录的上传处理,不过那时处理很简单。

首先是 form 要写正确,格式为:

<form enctype="multipart/form-data" method="POST" action="/address/upload/">

文件上传的input field的写法为:

<input type="file" name="file"/>

后台的处理是使用 request.FILES。它是一个Dict值,你可以:

file_obj = request.FILES.get(‘file’, None)

这里的’file’是与input field的名字一致的。如果file_obj不为空,它将是一个字典,通过测试可以得知它都有什么值。如果你参考 django 自带的 request_response.txt 文档,可以看到它主要有三个值:

  • content
    这是文件的内容
  • filename
    这是原文件名
  • content-type
    这是文件的mime类型

那么它放在哪里呢?应该是在内存中。因此接下来你可以对这个文件的内容进行处理了,是直接处理内容或保存到一个地方。

也许有人会问,那么 settings.py 中的 MEDIA_ROOT 是做什么用的。如果你不使用 django 的 Model 中的 FileField 或 ImageField 的话,它其实没有什么用。这个设置是用在 Model 的 FileField 中的。在创建一个 Model 时,如果你的 Model 中有与文件相关的字段,那么 django 会根据每个文件字段生成一系列的方法,如:get_fieldname_filename() get_fieldname_url() save_fieldname_file()。fieldname是根据你在 Model 中所起的名字来的。而 save_fieldname_file 需要两个参数,一个是文件名,另一个就是文件内容。因此,你可以使用这个方法来将上传的文件保存。那么保存到哪里去了呢?就是 MEDIA_ROOT 这个目录下。而 settings.py 中的 MEDIA_URL 就是用于 get_fieldname_url() 这个方法的。

因此,MEDIA_ROOT 只与 Model 有关。

2006年03月18日

目前对 django 提供的 Feed 框架做了自已的改造。一方面去掉了我认为没有必要的多余处理,比如:对于每个要处理的 object ,django要求提供一个模板,名为slug_title和slug_description,一个表示标题,一个表示内容,如果没有这两个模板,缺省使用 obj 来表示。我认为这非常不方便。一是:为什么不象其它的内容一样,通过定义相应的方法来返回,而非常使用模板呢?而且为什么只使用对象本身的表示,而不是限定对象的属性呢?我认为就是使用 obj.title 和 obj.description 也强于 obj 本身。另一方面我认为不合理的就是关于 domain 的处理,它通过 django 的 Site 这个 Model 来处理。但我认为这就带来的了定的限制,我认为合理的应该作为参数传入进来。因为用户可能使用 Site 来管理,也可能象我一样是在 settings.py 中进行设定的。还有象动态属性的处理,它会检查如果找到的属性是一个方法,而且还会判断这个方法的参数个数,以决定是否要传入参数。我认为控制好的话,根本不需要参数的传递。

因为我的改造一方面是去掉没有必要的东西,另一方面使得一些内容更加参数化,象domain,feed_url都作为参数。我还增加了一个prefix,作为可选的生成url的一个值。因为在 woodlog 的设计中,不用的 app 是可以通过不同的开始 url 进行区分的,比如 domain/blog 表示 blog 应用,domain/rss表示rss应用等。而每个app的内部的链接都默认为从某个应用的url为根进行处理的,因为它们都是根对于某相应用的url的相对路径。而这一点我在模板中是通过设定base值来控制的。对于 rss 的处理,为了生成完整的 url ,因此需要与应用相应的 prefix 的值,这样 domain/prefix/url 这样才是一个完整的值。当然prefix是可以省略的。

还有就是对于整个feed的一些动态属性基本没有变化,但对于item的属性我改为对于item对象来得到这些属性,而不是在feed类中定义一个接受obj的函数的方式。因此对于要处理的对象的要求高了一些,但我认为也有一些好处。为什么呢?因为一旦我修改了 Model ,那么因为对于 rss 的支持是在一起的,因此修改方便,而对于 rss 的处理本身却没有什么改动。而且一些 rss 的信息只是 Model 本身是最清楚的,也是最直接的获取方式。对于某个Feed的结果集还是要在 Feed 类本身的items()来提供。

具体的Feed的代码在utils/easyfeed.py中。然后我增加了一个 apps/rss 的应用,专门用来处理用户的索引feed和分类的feed。这一功能已经改造完成。