近两天对sae上用django做的网站进行了模板重构,本地运行正常,上传到sae之后出现模板无法找到的Bug,于是乎百度谷歌。 在国外的问答论坛上搜sae,基本上搜不到什么。在国内百度的话,也找不到什么有用的线索。 在寻找解决方案的过程中,发现了一个有趣的现象。虽然在国内以sae django 作为关键字搜索的话,能出来很多内容,但是看了之后就会发现,内容基本上都是一样的。 大多是从这个论坛搬到那个论坛,从这个博客转到那个博客,而且内容大多是参照djangobook的中文翻译,很难发现新的内容。 因此,我觉得将自己碰到的问题,和解决方案分享出来,是很有必要的,也是很有意义的。或许你所分享出来的东西,正是某些人所急需的。

  前几天,解决了Windows平台上django里面的makemessages命令无法更新的问题,主要难点是要在Windows上安装gettext,在解决这个问题的过程中,尝试使用了github上一个外国人制作的二进制安装包,结果提示找不到一个dll文件,试了几个办法都不行,于是乎在github上给那个开发者留言了,用生疏的英语告诉他缺少dll文件,该怎么办。没想到他几分钟之后就回复了(虽然我第二天才看到,因为那时已经是晚上11点多了,我没考虑到时差……),让我试试另一个二进制安装包。他还说他最近准备重新制作一个。虽然试了另一个也照样不管用,最后通过其他的方法解决了,但是意外的发现,我的github主页上增加了一条“Repositories you contribute to”记录。也许就是这样,你的提问,也是一种贡献。

关于版本和分支

sae上用数字区分版本。当时版本1已经完成了,准备建立版本2。那时还没有弄明白版本与分支的区别,就新建了一个分支,取名为2。 开发完成之后,上传到sae,在sae的代码管理面板里出现了一个版本2,我想当然的以为一切正常(事实上在本地跑就是一切正常)。 但是在浏览器输入链接,出错!错误提示是:ImportError: No module named Classmates。 看到网上有说是config.yaml里面的version空格问题,但是我都没改过这个,所以不是这个地方的问题。

关于version: 在config.yaml中,version:"1.5"之间要有一个空格。

最后终于找到原因了,问题就是出现在前面提到的分支与版本上。事实证明上面用建立分支的方法创造出来的版本,与在sae控制台上创建的版本是有区别的。我在sae上新建了一个版本,将代码拷贝到这个版本下,就能正常运行了。

模板继承

这两天把网站的模板重构了一下,以前的模板有很多重复冗余的内容,老早就想重构了,但是一直没有行动。上周末花了一天的时间,参照djangobook,现学现用,完成了模板的重构。 期间一切正常,没有出现什么麻烦的bug。本地调试完毕之后,上传到sae,输入链接,1秒之后,出现了错误信息,提示TemplateDoesNotExist。看下面给出的模板查询路径,位置也是对的,怎么能找不到模板了? 又是一番百度google,还在sae的论坛和豆瓣上sae python小组里面发帖求教,但是一直没有人回应。 在github上搜了一些sae django项目,看了他们的源码,很少使用了模板继承,有一些使用了模板继承的,但是目录结构与我的也不类似,也没有参考价值。 一切无果之后,我又新建了一个版本,将源码考到新版本下,上传,运行,正常!又是这样! 是不是sae上很多千奇百怪的问题都能用新建版本来解决?

内部信息保护

当我完成记住我的登录功能的时候,发现了一个新的问题。即在目前的网站中,很多核心的信息被暴露在用户面前。其中之一便是User表中的主键ID。 在当前的实现中,有些功能,我直接使用User表中的ID来查找对应的用户,然后进行一系列的操作,比如删除用户,查询用户信息等,我不知道这样做是否安全。 这些ID会被迁入在Html中,构成对应功能url的参数,这样一来,这些信息就会暴露给用户,只要一个用户登录后,查看html源码,就能很轻松的获取到其他用户的ID。 当然,这个ID只是用于后台数据库的增删改查,不能用来登录,所以,我所能想到的潜在隐患主要是可能会被用于SQL注入攻击。(Django本身提供了一些方法来防止SQL注入攻击) 我分析了一下其他一些网站的设计:

QQ空间: 在QQ空间中,很明显可以以QQ号作为参数,来实施各种操作,同样,QQ号也是暴露出来的。除此之外,QQ号也被用来作为登录的账号,所以,你与其他用户的信息的距离,只隔着一个密码。

新浪微博: 在新浪微博中,似乎有好几个值,可以作为参数,来实施增删改查。一个是昵称(参数名为onick),新浪微博的昵称是唯一的,不能重复,但是QQ中的昵称是可以重复的。一个是名为oid的数字ID,当然,还有一个名为uid的值应该也可以作为参数。以上三个似乎都不能用来登录。因此,在新浪微博中,别人需要知道你的账号和密码,才能窃取你的信息。

以上两者中都使用了昵称,昵称的可以用来隐藏真实身份,所以在QQ中,你能获取到一个QQ号,但是却不一定能知道这个QQ的主人是谁。我感觉,这也算是一种信息的保护吧。 在目前的设计中,我们没有使用昵称,而是直接显示真实姓名,因为我们这个网站一开始的定位是一个相互认识熟悉的人的圈子,因此,似乎不需要昵称。这样一来,一个网站实例只能提供一个圈子,若是要能提供任意个圈子,而且圈子与圈子之间要能实现信息隔离的话,似乎还得实现用户分组,以及考虑是否允许昵称等内容,而这些,似乎又是另外一个问题了。

模型的反向查找

昨天增加了一个模型,该模型中有两个字段是以User为外键,syncdb出错:Accessor for field <field name> clashes with field <field name>.查了一下官方手册,发现是因为反向查找集命名冲突。

class User(models.Model):
    pass

class Activity(models.Model):
    creator = models.ForeignKey('User')
    organizer = models.ForeignKey('User')
    pass

对于上面的ForeignKey域,Django会默认在User中增加一个用于反向查找Activity的域,名为activity_set 。这个域的作用是查找与User实例相关的所有Activity,使用方法ac = user.activity_set.all(),这样一来,对于上面两个ForeignKey域,就会产生两个activity_set,因此会产生冲突。 解决办法ForeignKey有一个related_name参数用于设置反向查找集的名字,可以将这两个修改成不同的名称,或者设为related_name='+',禁用反向查找。