2006年04月25日

DiveIntoPython 是一本由 Mark Pilgram 编写的一本关于 Python 学习的深入浅出的书。最新版本是 5.4 版。经过多人的努力终于正式发布。

整个项目由 Liang Osmond 带领,历经数月完成,最终以开源方式呈现给大家。感谢 Liang Osmond 的努力。

具体发布内容为:

Dive into Python 的官方中文版地址为 http://www.woodpecker.org.cn/diveintopython/

现在如果您访问 http://diveintopython.org/Chinese已经是新的地址了。

另外,Dive into Python 的官方中文版将纳入 Ubuntu 6.06 (Dapper),Ubuntu社区的 zhengpeng.hou (zhengpeng.hou AT gmail DOT com)正在制作并测试 deb 包,特表示感谢。

2006年04月24日

今天在 django 邮件列表中看到有人发了一封邮件,给出一个地址,然后让大家加入名字,地址是:

http://www.frappr.com/django

进去一看,有趣。是一个地图。把加入小组的人都以一个小图标标出来了,可以看出是哪个国家的。还可以上传自已的头像。以前没有用过,看着挺有趣。于是就加入进去。有兴趣的也加入啊。

为了学习 Ajax 我特意买了由 dlee 和其他几人翻译的《Ajax in Action》。这本书我正在看,感觉的确不错,有深有浅,特别适合我这种知道一些,但又对某些细节不是很了解的人。

在这本书中有关于MVC的讲述,通过实例来一点点分析什么样的MVC比较好。Controller代码与View代码混合在一起不便于维护,甚至象<a href="#" onclick="do_something();">这样的用法都认为是混在一起,并不好。最好是通过定位DOM元素来动态增加。这不仅让我想到了 MochiKit ,它的例子都是这样分离的。这样做的好处就是设计人员与开发人员互不干扰。prototype.js也一样可以做到。

前一阵子我一直在想如何在 django 中方便地自动生成 ajax 之类的代码,但经过一段时间的思考,我感觉我的想法还没有成熟,而且我也在寻找什么地方合适代码的自动生成。其实在 woodlog 中是有一些代码的自动生成,不过不是 ajax 相关的,而是生成如 Form 或 Table 之类的,而这些东西内容相对简单,目的明确,就是针对显示。但 Ajax 则不是这么容易,它包括交互处理,DOM处理,前后台交互,还有一些特效,这么多的东西哪些适合自动生成,哪些不适合自动生成呢?这个是我要考查的。

原本我设想了从表单入手,增加一个前端的js校验的处理。为此我还下载了不少的js校验的库。但现在又感觉我根本不需要。为什么呢?因为无论如何,为了增加系统的安全性,我都会在后台再次进行校验,而前端的校验是可有可无的。那么为什么它会出现呢?想来想去一个主要的原因就是,在不使用Ajax的异步通讯时,提交数据然后再反馈可能是一个漫长的过程,而且会占用一定的带宽。但采用ajax技术的话,从总体上带宽会相应减少,而且减少了前后台的多次校验,同时因为是异步处理,这一过程会显得非常平滑。因此我想我的重点反倒是如何处理前后台的交互和针对后台结果的前端处理。因此采不采用ajax技术会对你的设计有重大的影响。

特别是Ajax技术的应用可以分为许多种方式,有简单的点缀,有基于Ajax的技术,还有过度追求Ajax的技术。有的Ajax应用就是把浏览器当成客户端来处理,象Gmail,它有自已的一部分业务逻辑,这样造成大量的Ajax的枝术的使用,而后台只是返回数据,象这种自动生成代码是很难想象的,特别是还没有一个标准的Ajax的框架,采用何种框架来生成更是一个大问题。而且这种自动代码生成使得前端与后端结合得非常紧密,也未必是一件好事情。

经过这段时间的学习真是体会到 Ajax 技术对传统的 web 页面展示的冲击真是很大,我看到的不再是一个个相对独立的页面,而是一个功能完整的客户端,简单的请求,应答方式的处理很难适合Ajax的应用。所以如果你想使用 ajax 的技术,建议一开始就以 Ajax 的方式来思考。但这样的思考可能更多地体验在前端业务,显示逻辑的设计上。也许需要你对 js+css+DOM + ajax框架相对熟悉才行吧。

使用 Ajax 技术,需要学习的东西是更多了,但同时是一个挑战,而且这是做 web 的一个热点。

2006年04月21日

今天在 django 的主页和邮件列表中得知,Adrian 发出消息:

Django 团队倡议大家对 M-R 分枝进行测试,近期要集中精力修复各种bugs,不再增加新的特性,将于下周五与主干合并,待测试完成后将发布0.92版。同时还有一件重要的事情就是完善相关的文档,因为这是 Django 的一大“卖点”。

真是一个好消息,Django 终于要有新版本了。请我们期待吧。

Blog原文>>>

2006年04月19日

今天在 django 的邮件列表中看到一则消息 Google SOC: Call for Mentors 。在 pyxides 项目中就看到有人建议将这个项目弄到 Summer of Code 上去。到底这个 Summber of Code 是个什么东西。今天顺着 django 的这则新闻我好好的研究了一下。

原来就是 google 组织的一个活动,其目的是为了让学生有机会参与开源和自由软件的开发,并且是有薪水的。组织分为两部分,一部分是学生,一部分是指导团队。当然两者都是有一定的限制。比如你必须年满18周岁,并且是真正注册的在校学生,不过还包括了研究生,博士生之类的。团队的话需要先申请。那么方式就是由 google 资助符合条件的学生薪水,然后自由挑选喜欢的项目,完成指导团队提出的任务,并由导师给出意见。整个活动为期三个月,时间是从五月一日开始。据google的说明,去年就举行过一次。活动网站>>>

我上去看了一下,与python有关系的有:Django, MoinMoin, Plone, Python基金会。不管怎么样,Django在众多轻量级的web framework中应该说宣传工作做的是最好的了。在邮件列表中有人提到:在中国使用django的算是最多的,是不是与我的宣传有关系。我想一想的确是这样。

真是有意思的事情。

2006年04月18日

再次与 M-R 分枝相吻合。主要是更新了关于取消模板后缀引起的变化。同时去掉了 init 命令,改为 syncdb ,对各别地方所有补充和修改。

访问>>>

因为家里有事,所有关注得不是很多。从文档及代码的更新上可以看出有不少的变化。下面列出几点,看来我的教程也要做调整了。

  • 反向URL的解析。
    这个主要是为了解析当不同APP的集成问题。一般我们在URL上来区分不同的APP,因此每个APP在URL上都有一个前缀。然后在这个前缀上再是它的功能和对象的ID之类的信息。那么就存在一个问题,这个前缀如何方便设定和修改。涉及到这个前缀的地方可能有很多,象view, url, template甚至Model。如果修改了这个前缀,相关的地方都要进行修改。我在开发woodlog中就注意到了这个问题,我采用独立的配置,并提供了相应的API来处理,如在view中的API和模块中使用的Tag。现在已经有了一个解决的方案,在django/core/urlresolvers.py,不过还是有些复杂,而且对于template中使用的link还没有见到写在了什么地方。详情>>>
  • 备份django数据
    有人建议在admin中增加一个备份数据的功能。于是有人提问:为什么不使用数据库的备份功能。那么原因是数据库的备份功能无法保证跨数据库也可以使用。不过目前django开发小组已经在做这件事情了,好象完成了80%了。详情>>>
  • django中的电子商务。有人提问有没有相应的电子商务的应用存在,经过讨论创建了一个关门使用django来实现电子商务的邮件列表。详情>>> 电子商务邮件列表>>>
  • 模板后缀取消。这是非常大的一个变化。以前django的模板文件后缀默认为’.html’。而且在使用中你可以不用指定这个后缀。但经过讨论,决定是去掉对于后缀的默认处理。因此,以前对于模板中没有’.html’的地方都要增加。这个改动可不少。许多代码都要进行修改了。详情>>>
2006年04月16日

看到许多人都有,虽然我兴趣不大但是也想试一试。Google的东西的确很吸引人,我也不例外。大家有兴趣就点一下,没兴趣就算,呵呵。就当是一个游戏吧。

2006年04月13日

既然想用 Ajax ,那么就开始对功能一点点下手吧。第一件要考虑的事情,Ajax应用程度问题。过度的确不好,不过我现在的状态是学习,所以这个倒不是大问题。但合理总是要的。因为有些东西一旦变成Ajax的方式,可能就对搜索引擎不友好了。想一想对于管理功能其实可以考虑使用Ajax来实现。对于象明细之类的供别人看的可以部分做成Ajax的效果,这个可以在以后的开发中再总结。下面说一说在 Woodlog 中实现注销处理的 Ajax 的实现。实现的并不好,不过却是一个好的开始。

注销我主要考虑,当点击注销链接后发出一个 Ajax 请求,如果处理成功,则将注册区更新为未登录状态。因此这个处理包括了:

  • 链接的写法
  • Ajax调用处理
  • 后台的处理
  • 前面更新的处理

先说一下后台的处理。原来是使用 django 自带的 logout 的 View 代码,它只是简单地删除session中的用户的session_id,然后重定向到一个新的页面。因为采用了 Ajax 了,就不能再使用页面向导了,因为我们的目的是不离开当前页面。所以我在 public/account/views/main中增加了一个 logout 的 View 代码,很简单:

def logout(request):
    try:
        del request.session[SESSION_KEY]
    except:
        pass
    return HttpResponse(‘ok’)

这里我没有处理当session_key不存在的情况,只是为了简单。我也只是简单地返回一个’ok’而已。不过在前端我对这个串并没有处理。如果需要处理可以对它进行比较。再复杂点可能就要使用json了。不过这里用不着。

然后就是在模板中进行修改了。改一个就行了:apps/digest/templates/index.html。目前我只处理了 digest 首页的注销,woodlog 中的注销也是同理。

在页面上加入下面的javascript代码:

 <script type="text/javascript" src="{% get_app_root "medias" %}/prototype.js"></script>
 <script type="text/javascript">
  function show_waiting(ele){
   var a = new Insertion.Top(ele, ‘<img class="ajax_waiting" src="{% get_app_root "medias" %}/images/waiting.gif"/>’);
  }
  function stop_waiting(ele){
   var e = $(ele);
   var v = Element.extend(e.firstChild);
   if(v && v.nodeName == ‘IMG’ && v.hasClassName(‘ajax_waiting’))
    v.remove();
  }
  function do_logout(){
   show_waiting($(‘userinfo’));
   var a = new Ajax.Request(‘/logout/’, {
     onSuccess : function(resp) {
       $(‘userinfo’).innerHTML = ‘<a href="/login/" class="arrow">{% trans ‘Log in’ %}</a> <a href="/register/" class="arrow">{% trans ‘Register’ %}</a>’;
       stop_waiting(‘userinfo’);
     },
     onFailure : function(resp) {
       stop_waiting(‘userinfo’);
     }
    });
  }
 </script>

这段虽然是js代码,但因为是嵌在模板中的,因此会先进行模板处理,再输出,所以一样可以加入模板的处理。但对于有些需要在客户端处理的内容就无法处理了,因为执行是在前端。所以在后台输出的都是已经明确的东西。

我使用prototype.js库来进行处理。主要的工作就是在do_logout()函数中。它调用一个new AjaxRequest()处理来生成一个ajax请求对象,然后自动执行。在这里你可以注册两个方法,一个是成功,一个是失败。如果成功,则设定userinfo元素的内容(innerHTML)为未登录时的html代码。也就是说,登录区我使用一个span标签将两个链接包含起来,一个是登录/注册(这是未登录时的链接),或者是用户名/注销(这是登录成功后的链接)。这个span标签有一个id,值是userinfo。具体的代码是:

   <span id="userinfo">
            {% if user.is_anonymous %}
                <a href="/login/" class="arrow">{% trans ‘Log in’ %}</a> <a href="/register/" class="arrow">{% trans ‘Register’ %}</a>
            {% else %}
                <a href="/setting/" class="arrow">{{ user.username }}</a> | <a href="#" class="arrow" onclick="do_logout();return false;">{% trans ‘Sign out’ %}</a>
            {% endif %}</span>

从上面你可以看到如何在一个<a>中定义一个js函数。主要就是:

onclick="do_logout();return false;"

为什么要return false呢?因为不这样,链接就是生效,总返回false就不会实现跳转。当然还有其它几种形式。

更新一个标签的内容有许多种方式,可以使用DOM来处理,但相对复杂,最简单的就是设置一个标签的innerHTML属性即可。我采用的就是这种方式。

其实这样就已经足够了。但为了好看,我还加入了一个执行的指示器。其实就是一个小的gif动画。我的想法是:当执行ajax请求时显示这个小图片,当处理成功或失败时关闭这个小图片。那么这里的一个问题就是:如何增加一个图片,图片加到什么地方,如何删除这个图片。

BTW:在这里可以找到许多的Ajax指示图片,很有意思。

http://www.napyfab.com/ajax-indicators/

从上面的js代码你可以看出,我使用了两个函数:show_waiting和stop_waiting。show_waiting用来增加一个图片,它需要一个元素的名字。stop_waiting用来删除增加的图片,它也需要一个元素名字。那么你可以在不同的元素同时增加图片。

那么我想在userinfo这个span标签的最开始处加入这个图片,在页面上显示的效果就是当点击了注销时,在两个链接的前面会显示出这个图片。在prototype.js中提供了一个Insertion的类,它支持四种插入方式,如:Before这是插在元素的前面与元素平级,Top这是插在元素中,作为元素的第一个子元素,Bottom这是插在元素中,作为元素的最后一个子元素,After这是插在元素后面,与元素平级。你只要传入一个Html片段即可。于是show_waiting就是简单地把一个图片的html片段插入到了传入的元素的Top的位置。这里要注意,我并没有检查是否已经插入过一个ajax指示图片,因此这里还可以更完善一些。这样show_waiting就解决了前面提到的问题1和问题2。对于问题3是在stop_waiting中解决的。要删除一个元素,第一步是找到这个元素。因为指示图片需要是给定元素的第一个子元素。因此我使用ele.firstChild来得到第一个子元素。但要注意,firstChild是DOM本身提供的功能,并不是prototype.js提供的。而prototype.js有一个Element类,它提供了一个remove方法可以删除一个元素,当然不使用它也可以做到,可以直接使用DOM方法,使用Element的方法要简单得多。但ele.firstChild得到的并不是一个Element对象,因为不能使用remove方法,于是我使用Element.extend方法,将ele.firstChild转换为一个Element对象,然后再调用remove即可。但在调用remove之间我做了一些检查,主要是为了防止把不正确的东西也删除了。比如先检查得到的子元素是否存在,如果存在再看它的nodeName也就是检签的名字是不是IMG(好象DOM返回的元素的类型都是大写的),然后再看它是不是有一个叫’ajax_waiting’的class属性(这个属性是在插入img时在代码中设定的),如果条件都满足,然后才删除。

这里面其实有许多关于prototype.js的知识,我也是看了好几天才逐渐清楚一些。

工作基本上完成。这样当你点击注销时,如果处理不够快,会在前面显示一个小动画,如果成功,则显示为未登录的状态,如果失败则小图标消失,页面不变化。整个过程没有页面刷新,感觉速度就快多了。

另外我测试时一般都在FireFox下进行,结果转到IE下有错误。但IE没有FireFox一样的插件可以方便调试,结果查了半天的程序,发现:

  1. 字典数据的定义,在最后一个元素后面不能有’,'。而在FF下没有问题,但IE下有问题。
  2. IE的Cache很烦人,有时结果不发生变化。最好只好把cookie和保存的历史数据删除才可以。

不管怎么样,第一个在 djangocn.org 上的 Ajax 小功能算是成功了。下一步考虑使用 Window (一个Ajax的代码)来实现登录,注册的窗口效果,这样不用进入其它的页面了。

2006年04月12日

这是一个 Firefox 的插件,很早也装过,只是不知道有什么用,而且看着状态条上一堆堆的错误计数挺烦人,再加上好象浏览器会变慢,于是就删除了。后来在 Ajaxcn 上看到更新到 3.0 了,说是功能更强大了。再加上现在在学习 Ajax ,于是乎又装了一个。用了几天,慢慢发现果然好使。

首先它可以自动监控所浏览网页的内容,然后报告错误。哪些错误被显示可以在它的菜单中设置,比如:显示javascript的错误,显示CSS的错误,显示chrome的错误等。然后主界面分为 Console 和 Inspector 。在Console 中主要是显示错误,同时下面还有一个命令输入框可以输入命令进行测试。它可以直接使用所在页面的 js 代码,做些简单的测试非常方便。更强大的还是 Inspector 。切换到 Inspector 后,在窗口的下面还有几个 tag 标签,有:source, style, layout, events, dom。都非常有用。

Source 它可以看到当前页面的内容。注意,这可是经过浏览器处理后的真正的内容,并不完全是原始的页面。象gmail的页面使用它可以看到有许多的frame在里面。而通过查看源代码是看不到的。有些象动态生成的标签也可以看得到,非常好。在source中,元素按照嵌套关系以树状形式排列,可以打开看到子元素。如果是一个可见的元素,当鼠标在某些元素上移动时可以看到在页面上的相应的元素周围会有一个蓝框,这样就可以看到元素的位置和大小了。如果你再点击左上角的 Inspect 菜单,你甚至可以在页面中移动鼠标时,鼠标下面的元素会自动显示蓝框,而且下面的 FireBug 的窗口内容在自动发生变化。真是太Cool了。

Style 不知道有什么用。

Layout 也可能比较有用,可以看到元素的位置信息。

Events 也不知道有什么用。

Dom 用处很大,可以看它当前元素的所有属性和方法。有些不知道的东西或记不清的东西可以让它帮助你回忆。

选中当前元素的方法其实有两种,一种是在source中的元素标签上点击,然后再切换到 Layout, Dom看内容。另一种就是点击左上角的 Inspect ,然后在页面上动态选择元素,这个可能更方便。

同时对于它报告的错误,比如Js或CSS的错误,还可以跳转到出错的位置,我使用它还发现了 woodlog 的几个CSS错误。

在 Console 中,它还可以监控XMLHttpRequest的调用。而且我感觉它的命令行很有用,可以直接用它来测试你的页面。因为它可以直接调用当前页面已经装入的 js 代码库,你可以使用它去修改内容。好处多多啊。

如果平时不想用,还可以在 Tools 中它的菜单下将其 Disable 掉。想用的时候再打开。

同时它还提供了几个快捷键可以使用,看一下它的菜单就知道了。

这个东西用来调试动态的内容真是太方便了。强烈推荐使用。