<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>林胜的记事本</title>
	<atom:link href="http://blog.linsheng.me/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.linsheng.me</link>
	<description></description>
	<pubDate>Thu, 01 Apr 2010 23:29:18 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>在django中把单元测试分散到多个文件中</title>
		<link>http://blog.linsheng.me/archives/63.html</link>
		<comments>http://blog.linsheng.me/archives/63.html#comments</comments>
		<pubDate>Thu, 01 Apr 2010 23:27:06 +0000</pubDate>
		<dc:creator>林胜</dc:creator>
		
		<category><![CDATA[我爱编程]]></category>

		<guid isPermaLink="false">http://blog.linsheng.me/archives/63.html</guid>
		<description><![CDATA[在django中编写单元测试的时候，django默认是到应用的目录下的tests.py中查找unittest.TestCase的子类来运行测试的。这样，我们就需要把这个应用的所有测试都写在tests.py中，如果测试比较多的话，这个文件就会非常大。其实我们完全可以把测试写到其他的文件中，只要在tests.py中引用这些文件中的测试类就可以了。
比如，我们可以把所有有关Book的测试放到book_tests.py中，然后在tests.py中import这个文件中的测试类, 这样就解决掉只能在tests.py中写测试的限制了。
[python]
# tests.py
from book_tests import *
[/python]
]]></description>
			<content:encoded><![CDATA[<p>在django中编写单元测试的时候，django默认是到应用的目录下的tests.py中查找unittest.TestCase的子类来运行测试的。这样，我们就需要把这个应用的所有测试都写在tests.py中，如果测试比较多的话，这个文件就会非常大。其实我们完全可以把测试写到其他的文件中，只要在tests.py中引用这些文件中的测试类就可以了。</p>
<p>比如，我们可以把所有有关Book的测试放到book_tests.py中，然后在tests.py中import这个文件中的测试类, 这样就解决掉只能在tests.py中写测试的限制了。</p>
<p>[python]<br />
# tests.py<br />
from book_tests import *<br />
[/python]</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.linsheng.me/archives/63.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>在Django view中设置ModelChoiceField的选项</title>
		<link>http://blog.linsheng.me/archives/60.html</link>
		<comments>http://blog.linsheng.me/archives/60.html#comments</comments>
		<pubDate>Fri, 19 Mar 2010 03:33:48 +0000</pubDate>
		<dc:creator>林胜</dc:creator>
		
		<category><![CDATA[我爱编程]]></category>

		<guid isPermaLink="false">http://blog.linsheng.me/?p=60</guid>
		<description><![CDATA[我们在使用Django中的ModelChoiceField时，可以通过queryset选项来设置这个字段对应的选项。通常这个queryset的设置都是在form中定义form类的时候来使用。其实，我们也可以在view中设置queryset，这样就给了我们更加灵活的控制。比如我们有下面的类:
[python]
class Category(models.Model):
    user = models.ForeignKey(User, related_name=&#8221;categories&#8221;)
    name = models.CharField(max_length=50)
class Book(models.Model):
    category = models.ForeignKey(Category)
    name = models.CharField(max_length=50)
class BookForm(form.ModelForm):
    class Meta:
        model = Book
[/python]
在Book类中，把category作为一个外键，当我们使用ModelForm时，会自动使用ModelChoiceField，而这个Field的选项默认就是全部的目录。如果我们的需求是要把选项限制在当前登录用户创建的目录时，我们就需要动态来设置这个字段的选项。我们可以在view中通过下面的方式来实现：

[python]
def create_book(request):
    form = BookForm()
    form.base_fields['category'].queryset [...]]]></description>
			<content:encoded><![CDATA[<p>我们在使用Django中的ModelChoiceField时，可以通过queryset选项来设置这个字段对应的选项。通常这个queryset的设置都是在form中定义form类的时候来使用。其实，我们也可以在view中设置queryset，这样就给了我们更加灵活的控制。比如我们有下面的类:</p>
<p>[python]<br />
class Category(models.Model):<br />
    user = models.ForeignKey(User, related_name=&#8221;categories&#8221;)<br />
    name = models.CharField(max_length=50)</p>
<p>class Book(models.Model):<br />
    category = models.ForeignKey(Category)<br />
    name = models.CharField(max_length=50)</p>
<p>class BookForm(form.ModelForm):<br />
    class Meta:<br />
        model = Book<br />
[/python]</p>
<p>在Book类中，把category作为一个外键，当我们使用ModelForm时，会自动使用ModelChoiceField，而这个Field的选项默认就是全部的目录。如果我们的需求是要把选项限制在当前登录用户创建的目录时，我们就需要动态来设置这个字段的选项。我们可以在view中通过下面的方式来实现：</p>
<p>
[python]<br />
def create_book(request):<br />
    form = BookForm()<br />
    form.base_fields['category'].queryset = request.user.categories.all()<br />
    &#8230;&#8230;<br />
[/python]</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.linsheng.me/archives/60.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>在Django中配置本地设置</title>
		<link>http://blog.linsheng.me/archives/56.html</link>
		<comments>http://blog.linsheng.me/archives/56.html#comments</comments>
		<pubDate>Fri, 05 Mar 2010 07:44:18 +0000</pubDate>
		<dc:creator>林胜</dc:creator>
		
		<category><![CDATA[我爱编程]]></category>

		<guid isPermaLink="false">http://blog.linsheng.me/?p=56</guid>
		<description><![CDATA[在Django项目中，我们一般都会把配置信息放置在settings.py中。在一个多人的项目中，可能某些设置项每个人的配置会不相同。比如MEDIA_ROOT，没法要求每个开发人员都使用相同的路径。那当开发人员开发的时候，他就需要在不修改settings.py的情况下，来使用自己的本地配置。解决的方法就是在本地创建一个local_settings.py文件，然后在settings.py中引用这个文件。把下面的代码放到settings.py的最后:
[python]
try:
    from local_settings import *
except
    ImportError: pass
[/python]
这样，把本地的设置项放置到local_settings.py中，就可以覆盖settings.py中的配置。而settings.py中可以放置部署时的设置，这样在部署时，就不需要做额外的修改。
]]></description>
			<content:encoded><![CDATA[<p>在Django项目中，我们一般都会把配置信息放置在settings.py中。在一个多人的项目中，可能某些设置项每个人的配置会不相同。比如MEDIA_ROOT，没法要求每个开发人员都使用相同的路径。那当开发人员开发的时候，他就需要在不修改settings.py的情况下，来使用自己的本地配置。解决的方法就是在本地创建一个local_settings.py文件，然后在settings.py中引用这个文件。把下面的代码放到settings.py的最后:</p>
<p>[python]<br />
try:<br />
    from local_settings import *<br />
except<br />
    ImportError: pass<br />
[/python]</p>
<p>这样，把本地的设置项放置到local_settings.py中，就可以覆盖settings.py中的配置。而settings.py中可以放置部署时的设置，这样在部署时，就不需要做额外的修改。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.linsheng.me/archives/56.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>失业了</title>
		<link>http://blog.linsheng.me/archives/55.html</link>
		<comments>http://blog.linsheng.me/archives/55.html#comments</comments>
		<pubDate>Mon, 01 Feb 2010 12:02:30 +0000</pubDate>
		<dc:creator>林胜</dc:creator>
		
		<category><![CDATA[啰啰嗦嗦]]></category>

		<guid isPermaLink="false">http://blog.linsheng.me/?p=55</guid>
		<description><![CDATA[经国家批准，我正式失业了。

  

]]></description>
			<content:encoded><![CDATA[<p>经国家批准，我正式失业了。</p>
<div style="text-align: center;">
  <img src="http://blog.linsheng.me/wp-content/uploads/2010/02/shiyezheng.jpg" width="286" height="393" alt="shiyezheng.jpg" />
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.linsheng.me/archives/55.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>32 or 64, that is the question</title>
		<link>http://blog.linsheng.me/archives/53.html</link>
		<comments>http://blog.linsheng.me/archives/53.html#comments</comments>
		<pubDate>Sat, 23 Jan 2010 05:28:36 +0000</pubDate>
		<dc:creator>林胜</dc:creator>
		
		<category><![CDATA[我爱编程]]></category>

		<guid isPermaLink="false">http://blog.linsheng.me/?p=53</guid>
		<description><![CDATA[这两天在雪豹上安装PostgreSQL和pyscopg2，差点没被折腾死。由于雪豹的内核升级到了64位并兼容32位，所以在雪豹上运行的应用程序就会有64位和32位这两种情况。而要想让Python, PostgreSQL和pyscopg2正确的运行，最根本的一点就是要让它们都以相同的方式运行。
由于PostgreSQL现在还没有提供64位的安装版本，所以也就需要Python，PostgreSQL和pyscopg2全部以32位的方式来运行。下面就是一些在安装中需要注意的地方。
1. 让Python以32位运行。雪豹上自带的Python版本为2.6.1，并且默认是以64位的方式来运行。所以，我们首先要把Python以32位的方式来运行。只要在命令行中输入下面的命令就可以了：

$ defaults write com.apple.versioner.python Prefer-32-Bit -bool yes

2. 安装PostgreSQL，这个安装当中没有特别需要注意的地方，下载下来运行安装包就可以了。
3. 安装pyscopg2。这是最麻烦的一步。首先，要修改setup.cfg中pg_config的路径。如果你在安装PostgreSQL时使用了默认安装，那pg_config的路径应该是/Library/PostgreSQL/8.4/bin/pg_config。

pg_config=/Library/PostgreSQL/8.4/bin/pg_config

修改完毕后，要用32位的方式来编译和安装pyscopg2。

ARCHFLAGS=&#8217;-arch i386&#8242; python setup.py build
ARCHFLAGS=&#8217;-arch i386&#8242; python setup.py install

通过上面的步骤，基本上就可以保证Python，PostgreSQL和pyscopg2能够正常工作了。
其实除了PostgreSQL和pyscopg2，在雪豹上安装Mysql和Mysqldb时，同样也会遇到这样的问题。但是Mysql的情况稍微复杂，因为Mysql有64位和32位两种版本。但是最根本的一条就是要保证这些程序都以相同的方式编译和运行就可以了。

]]></description>
			<content:encoded><![CDATA[<p>这两天在雪豹上安装PostgreSQL和pyscopg2，差点没被折腾死。由于雪豹的内核升级到了64位并兼容32位，所以在雪豹上运行的应用程序就会有64位和32位这两种情况。而要想让Python, PostgreSQL和pyscopg2正确的运行，最根本的一点就是要让它们都以相同的方式运行。</p>
<p>由于PostgreSQL现在还没有提供64位的安装版本，所以也就需要Python，PostgreSQL和pyscopg2全部以32位的方式来运行。下面就是一些在安装中需要注意的地方。</p>
<p>1. 让Python以32位运行。雪豹上自带的Python版本为2.6.1，并且默认是以64位的方式来运行。所以，我们首先要把Python以32位的方式来运行。只要在命令行中输入下面的命令就可以了：</p>
<blockquote>
<p>$ defaults write com.apple.versioner.python Prefer-32-Bit -bool yes</p>
</blockquote>
<p>2. 安装PostgreSQL，这个安装当中没有特别需要注意的地方，下载下来运行安装包就可以了。</p>
<p>3. 安装pyscopg2。这是最麻烦的一步。首先，要修改setup.cfg中pg_config的路径。如果你在安装PostgreSQL时使用了默认安装，那pg_config的路径应该是/Library/PostgreSQL/8.4/bin/pg_config。</p>
<blockquote>
<p>pg_config=/Library/PostgreSQL/8.4/bin/pg_config</p>
</blockquote>
<p>修改完毕后，要用32位的方式来编译和安装pyscopg2。</p>
<blockquote>
<p>ARCHFLAGS=&#8217;-arch i386&#8242; python setup.py build</p>
<p>ARCHFLAGS=&#8217;-arch i386&#8242; python setup.py install</p>
</blockquote>
<p>通过上面的步骤，基本上就可以保证Python，PostgreSQL和pyscopg2能够正常工作了。</p>
<p>其实除了PostgreSQL和pyscopg2，在雪豹上安装Mysql和Mysqldb时，同样也会遇到这样的问题。但是Mysql的情况稍微复杂，因为Mysql有64位和32位两种版本。但是最根本的一条就是要保证这些程序都以相同的方式编译和运行就可以了。</p>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.linsheng.me/archives/53.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Go le? 够了？</title>
		<link>http://blog.linsheng.me/archives/52.html</link>
		<comments>http://blog.linsheng.me/archives/52.html#comments</comments>
		<pubDate>Thu, 14 Jan 2010 07:23:07 +0000</pubDate>
		<dc:creator>林胜</dc:creator>
		
		<category><![CDATA[啰啰嗦嗦]]></category>

		<guid isPermaLink="false">http://blog.linsheng.me/?p=52</guid>
		<description><![CDATA[今天，g.cn首页的图片换成了四大发明。设计非常巧妙。四大发明分别替换了G O L E四个字母，留下O G两个字母。联想到Google要退出中国的声明，不禁让人联系翩翩。Go了？走了？(受)够了？哈哈&#8230;

]]></description>
			<content:encoded><![CDATA[<p>今天，g.cn首页的图片换成了四大发明。设计非常巧妙。四大发明分别替换了G O L E四个字母，留下O G两个字母。联想到Google要退出中国的声明，不禁让人联系翩翩。Go了？走了？(受)够了？哈哈&#8230;</p>
<p style="text-align: center;"><img src="http://blog.linsheng.me/wp-content/uploads/2010/01/screen-shot-2010-01-14-at-31737-pm.png" width="549" height="227" alt="Screen shot 2010-01-14 at 3.17.37 PM.png" style="border:1px #000000 dotted;" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.linsheng.me/archives/52.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>谷歌一出，春哥失色</title>
		<link>http://blog.linsheng.me/archives/50.html</link>
		<comments>http://blog.linsheng.me/archives/50.html#comments</comments>
		<pubDate>Thu, 14 Jan 2010 03:12:47 +0000</pubDate>
		<dc:creator>林胜</dc:creator>
		
		<category><![CDATA[啰啰嗦嗦]]></category>

		<guid isPermaLink="false">http://blog.linsheng.me/?p=50</guid>
		<description><![CDATA[这两天网上铺天盖地的都是关于Google要退出中国的消息和评论，在这里也记录一下自己的感想。

谷歌是纯爷们。刚听到这个消息的时候，我真有点想要鼓掌的冲动。因为这是中国任何一家公司都不会，也不可能作出来的。而谷歌的声明，也着实为我们这些长期受到GFW压抑的中国网民出了一口恶气。就像网友说的，这次谷歌是做够太监了，准备回家当纯爷们了。
要抓紧时间学习翻墙本领了。谷歌这样的做法，肯定会激怒那些一贯养尊处优的官爷们，所以退出中国市场，应该是板上钉钉了。而且很快，Google的一系列服务很可能会被屏蔽到墙外了。Facebook我可以不上，Youtube我可以不看，Twitter我可以不聊，但是不用Google搜索，不用GMail，没有Google Reader，那还怎么活啊。可以肯定的是，如果Google真的退出中国市场，中国的网民将迎来新一轮的翻墙技术学习热潮。我也要赶紧攒点钱，在需要的时候，去买点VPN了。
做好移民准备。如果最后连墙也翻不过去了，那只能移民了。哎&#8230;


]]></description>
			<content:encoded><![CDATA[<p>这两天网上铺天盖地的都是关于Google要退出中国的消息和评论，在这里也记录一下自己的感想。</p>
<ol>
<li>谷歌是纯爷们。刚听到这个消息的时候，我真有点想要鼓掌的冲动。因为这是中国任何一家公司都不会，也不可能作出来的。而谷歌的声明，也着实为我们这些长期受到GFW压抑的中国网民出了一口恶气。就像网友说的，这次谷歌是做够太监了，准备回家当纯爷们了。</li>
<li>要抓紧时间学习翻墙本领了。谷歌这样的做法，肯定会激怒那些一贯养尊处优的官爷们，所以退出中国市场，应该是板上钉钉了。而且很快，Google的一系列服务很可能会被屏蔽到墙外了。Facebook我可以不上，Youtube我可以不看，Twitter我可以不聊，但是不用Google搜索，不用GMail，没有Google Reader，那还怎么活啊。可以肯定的是，如果Google真的退出中国市场，中国的网民将迎来新一轮的翻墙技术学习热潮。我也要赶紧攒点钱，在需要的时候，去买点VPN了。</li>
<li>做好移民准备。如果最后连墙也翻不过去了，那只能移民了。哎&#8230;</li>
</ol>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.linsheng.me/archives/50.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>用户模块功能与流程</title>
		<link>http://blog.linsheng.me/archives/28.html</link>
		<comments>http://blog.linsheng.me/archives/28.html#comments</comments>
		<pubDate>Mon, 11 Jan 2010 07:54:12 +0000</pubDate>
		<dc:creator>林胜</dc:creator>
		
		<category><![CDATA[我爱编程]]></category>

		<guid isPermaLink="false">http://blog.linsheng.me/?p=28</guid>
		<description><![CDATA[表结构
users表：用于保存用户信息。



id
int(11)
PrimaryKey


username
varchar(32)
用户名


password
char(50)
密码


name
varchar(50)
名字


email
varchar(127)
邮件地址


logins
int(10)
登录次数


last_login
timestamp
最后登录时间




user_pendings表：用户email地址验证信息。



id
int(10)
PrimaryKey


user_id
int(10)
用户id


token
char(10)
用于验证的随即字符串


created_date
timestamp
创建时间



roles表：角色表。在角色表中可预先插入系统中预置的角色，如&#8217;login&#8217;角色，拥有此角色的用户可以登录到系统中。



id
int(11)
PrimaryKey


name
varchar(30)
角色名称


description
varchar(100)
描述




roles_users表：users表和roles表的多对多对应表。



role_id
int(11)


user_id
int(11)




功能与流程
一、 用户注册

显示用户注册界面。
用户填写注册信息，并提交。
系统通过Javascript对注册信息进行验证。包括：

非空验证。像用户名、密码、email等信息不能为空。
长度验证。验证数据长度是否过短或过长。
两次输入的密码是否相同。
email地址的格式是否合法。
通过Ajax验证用户名是否存在。（可选，也可以提交到后台验证）
通过Ajax验证email地址是否已经被使用。（可选，可以提交到后台验证）


数据如果未通过验证，显示错误信息，并重复步骤2、3。
如果前台数据验证通过，则将数据提交到后台，进行后台数据验证。后台数据验证的方面和前台相同。
如果数据未通过后台验证，则返回用户注册页面，并显示所有的错误信息，让用户对信息进行修改。重复步骤2、3、4、5。
如果数据通过了后台验证，就将用户注册的信息保存到users表中，但是不要给这个用户添加任何角色。在添加纪录前，要将密码加密后再保存到数据库中。
用户保存完毕后，生成一个10位的随即字符串，把字符串和用户的id组合到一个url中，如http://xxx.com/user/15/verify/ad89d09uu2。把这个url发送给用户注册时使用的email地址，告知用户通过点击这个链接，就可以完成注册的认证。
发出email后，将user id和生成的这个随即字符串(token)保存到user_pendings表中。
显示注册成功页面。

二、验证用户email地址

用户点击收到的验证邮件中的验证链接。
根据url中用户的id，到user_pendings表中查找是否存在这个验证信息。如果不存在，显示验证失败页面。
如果验证信息存在，对比url中的token和这个用户在user_pendings表中的token是否相同。如果不相同，显示验证失败页面。
如果token也相同，则查看token生成的日期是否已经超过了系统规定的token失效时间，比如24小时。如果token失效，则显示验证失败页面。
如果token未过期，则将&#8217;login&#8217;角色赋给当前用户，使用户可以具有登录的权限。
将user_pendings中此用户的验证信息删除。
显示验证成功页面（或登录页面）。

三、用户登录

显示用户登录页面。
用户输入用户名和密码，点击“登录”按钮进行登录。
通过Javascript进行前台数据验证。包括：

用户名和密码不能为空。
用户名和密码的长度不能过长或过短。


如果前台验证失败，则显示所有错误信息，回到步骤2。
如果前台验证通过，则进入后台验证。系统通过用户输入的用户名，在users表中查找这个用户是否存在。如果不存在，则显示登录失败页面，让用户重新登录。
如果用户存在，则对比用户输入的密码是否正确。如果密码错误，显示登录失败页面，让用户重新登录。
如果密码正确，则察看此用户是否具有&#8217;login&#8217;角色。如果没有，则提示用户没有登录的权限。
如果用户有&#8217;login&#8217;的角色，则将用户信息保存到session中，并显示登录成功页面。

]]></description>
			<content:encoded><![CDATA[<h3>表结构</h3>
<p>users表：用于保存用户信息。</p>
<table width="100%" border="1">
<tbody>
<tr>
<td>id</td>
<td>int(11)</td>
<td>PrimaryKey</td>
</tr>
<tr>
<td>username</td>
<td>varchar(32)</td>
<td>用户名</td>
</tr>
<tr>
<td>password</td>
<td>char(50)</td>
<td>密码</td>
</tr>
<tr>
<td>name</td>
<td>varchar(50)</td>
<td>名字</td>
</tr>
<tr>
<td>email</td>
<td>varchar(127)</td>
<td>邮件地址</td>
</tr>
<tr>
<td>logins</td>
<td>int(10)</td>
<td>登录次数</td>
</tr>
<tr>
<td>last_login</td>
<td>timestamp</td>
<td>最后登录时间</td>
</tr>
</tbody>
</table>
<p></p>
<p>user_pendings表：用户email地址验证信息。</p>
<table width="100%" border="1">
<tbody>
<tr>
<td>id</td>
<td>int(10)</td>
<td>PrimaryKey</td>
</tr>
<tr>
<td>user_id</td>
<td>int(10)</td>
<td>用户id</td>
</tr>
<tr>
<td>token</td>
<td>char(10)</td>
<td>用于验证的随即字符串</td>
</tr>
<tr>
<td>created_date</td>
<td>timestamp</td>
<td>创建时间</td>
</tr>
</tbody>
</table>
<p>roles表：角色表。在角色表中可预先插入系统中预置的角色，如&#8217;login&#8217;角色，拥有此角色的用户可以登录到系统中。</p>
<table border="1" width="100%">
<tbody>
<tr>
<td>id</td>
<td>int(11)</td>
<td>PrimaryKey</td>
</tr>
<tr>
<td>name</td>
<td>varchar(30)</td>
<td>角色名称</td>
</tr>
<tr>
<td>description</td>
<td>varchar(100)</td>
<td>描述</td>
</tr>
</tbody>
</table>
<p></p>
<p>roles_users表：users表和roles表的多对多对应表。</p>
<table border="1" width="100%">
<tbody>
<tr>
<td>role_id</td>
<td>int(11)</td>
</tr>
<tr>
<td>user_id</td>
<td>int(11)</td>
</tr>
</tbody>
</table>
<h3></h3>
<h3>功能与流程</h3>
<p><b>一、 用户注册</b></p>
<ol>
<li>显示用户注册界面。</li>
<li>用户填写注册信息，并提交。</li>
<li>系统通过Javascript对注册信息进行验证。包括：
<ul>
<li>非空验证。像用户名、密码、email等信息不能为空。</li>
<li>长度验证。验证数据长度是否过短或过长。</li>
<li>两次输入的密码是否相同。</li>
<li>email地址的格式是否合法。</li>
<li>通过Ajax验证用户名是否存在。（可选，也可以提交到后台验证）</li>
<li>通过Ajax验证email地址是否已经被使用。（可选，可以提交到后台验证）</li>
</ul>
</li>
<li>数据如果未通过验证，显示错误信息，并重复步骤2、3。</li>
<li>如果前台数据验证通过，则将数据提交到后台，进行后台数据验证。后台数据验证的方面和前台相同。</li>
<li>如果数据未通过后台验证，则返回用户注册页面，并显示所有的错误信息，让用户对信息进行修改。重复步骤2、3、4、5。</li>
<li>如果数据通过了后台验证，就将用户注册的信息保存到users表中，但是不要给这个用户添加任何角色。在添加纪录前，要将密码加密后再保存到数据库中。</li>
<li>用户保存完毕后，生成一个10位的随即字符串，把字符串和用户的id组合到一个url中，如http://xxx.com/user/15/verify/ad89d09uu2。把这个url发送给用户注册时使用的email地址，告知用户通过点击这个链接，就可以完成注册的认证。</li>
<li>发出email后，将user id和生成的这个随即字符串(token)保存到user_pendings表中。</li>
<li>显示注册成功页面。</li>
</ol>
<p><b>二、验证用户email地址</b></p>
<ol>
<li>用户点击收到的验证邮件中的验证链接。</li>
<li>根据url中用户的id，到user_pendings表中查找是否存在这个验证信息。如果不存在，显示验证失败页面。</li>
<li>如果验证信息存在，对比url中的token和这个用户在user_pendings表中的token是否相同。如果不相同，显示验证失败页面。</li>
<li>如果token也相同，则查看token生成的日期是否已经超过了系统规定的token失效时间，比如24小时。如果token失效，则显示验证失败页面。</li>
<li>如果token未过期，则将&#8217;login&#8217;角色赋给当前用户，使用户可以具有登录的权限。</li>
<li>将user_pendings中此用户的验证信息删除。</li>
<li>显示验证成功页面（或登录页面）。</li>
</ol>
<p><b>三、用户登录</b></p>
<ol>
<li>显示用户登录页面。</li>
<li>用户输入用户名和密码，点击“登录”按钮进行登录。</li>
<li>通过Javascript进行前台数据验证。包括：
<ul>
<li>用户名和密码不能为空。</li>
<li>用户名和密码的长度不能过长或过短。</li>
</ul>
</li>
<li>如果前台验证失败，则显示所有错误信息，回到步骤2。</li>
<li>如果前台验证通过，则进入后台验证。系统通过用户输入的用户名，在users表中查找这个用户是否存在。如果不存在，则显示登录失败页面，让用户重新登录。</li>
<li>如果用户存在，则对比用户输入的密码是否正确。如果密码错误，显示登录失败页面，让用户重新登录。</li>
<li>如果密码正确，则察看此用户是否具有&#8217;login&#8217;角色。如果没有，则提示用户没有登录的权限。</li>
<li>如果用户有&#8217;login&#8217;的角色，则将用户信息保存到session中，并显示登录成功页面。</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blog.linsheng.me/archives/28.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>第一届中国iPhone开发者技术交流大会记</title>
		<link>http://blog.linsheng.me/archives/24.html</link>
		<comments>http://blog.linsheng.me/archives/24.html#comments</comments>
		<pubDate>Sat, 12 Sep 2009 13:40:56 +0000</pubDate>
		<dc:creator>林胜</dc:creator>
		
		<category><![CDATA[啰啰嗦嗦]]></category>

		<guid isPermaLink="false">http://blog.linsheng.me/?p=24</guid>
		<description><![CDATA[今天，去参加了由CocoaChina和China-Pub联合举办的第一届中国iPhone开发者技术交流大会。知道iPhone开发正在中国慢慢兴起，但是到了会场，还是被200多的参加人数惊了一下。而主办方好像也没有想到会有这么多人，会场座位不够，以至最后有的同学只能站着听讲座。
这次大会的演讲者都是第一线的iPhone开发人员，都有多个产品在App Store中发布，技术水准和实战经验相当丰富。而演讲主题从数据处理到Core Animation，从第三方控件到多点触摸，个个技术含量十足。相信在场的iPhone开发人员肯定会打呼过瘾。而像我这样的门外汉，也对iPhone的开发和开发社区有了更具象的认识。
当天的话题中，有两个印象比较深。一个张庆伟介绍的iPhone的数据处理，介绍了通过分离读写数据库来解决大数据库的问题，在我的提问中，他建议使用索引来提高查询速度，并且当数据量过大（超过2500条）时，会出现数据查询的延迟。
另外一个演讲时许向军带来的iFighter成功经验。他的演讲中最让我认同的一点就是精品思路，做东西一定要做精品，真真正正的做好产品。在竞争日趋激烈，气氛越来越浮躁的iPhone开发大军中，保持冷静的头脑和坚定的信念，才是成功的基石。
由于是第一届大会，当然也出现了写不足的地方。比较明显的，也是很多技术大会中遇到的问题，就是由于演讲者机会都是技术人员，而且有些可能是第一次面对这么多人演讲，难免有些紧张，导致表达的效果不够理想。而主办方可能是由于时间过于仓促，有些地方也不够周到。场地小，座位太少，话筒经常失灵，投影不清楚等也给大会的效果带来了少许影响。当然，瑕不掩瑜，相信这些问题在以后的大会中，都会有所改善。
本次大会的所有演讲稿都已经放出，请猛击这里。
]]></description>
			<content:encoded><![CDATA[<p>今天，去参加了由<a href="http://www.cocoachina.com/" target="_blank" title="http://www.cocoachina.com/">CocoaChina</a>和<a href="http://www.china-pub.com/" target="_blank" title="http://www.china-pub.com/">China-Pub</a>联合举办的第一届中国iPhone开发者技术交流大会。知道iPhone开发正在中国慢慢兴起，但是到了会场，还是被200多的参加人数惊了一下。而主办方好像也没有想到会有这么多人，会场座位不够，以至最后有的同学只能站着听讲座。</p>
<p>这次大会的演讲者都是第一线的iPhone开发人员，都有多个产品在App Store中发布，技术水准和实战经验相当丰富。而演讲主题从数据处理到Core Animation，从第三方控件到多点触摸，个个技术含量十足。相信在场的iPhone开发人员肯定会打呼过瘾。而像我这样的门外汉，也对iPhone的开发和开发社区有了更具象的认识。</p>
<p>当天的话题中，有两个印象比较深。一个张庆伟介绍的iPhone的数据处理，介绍了通过分离读写数据库来解决大数据库的问题，在我的提问中，他建议使用索引来提高查询速度，并且当数据量过大（超过2500条）时，会出现数据查询的延迟。</p>
<p>另外一个演讲时许向军带来的iFighter成功经验。他的演讲中最让我认同的一点就是精品思路，做东西一定要做精品，真真正正的做好产品。在竞争日趋激烈，气氛越来越浮躁的iPhone开发大军中，保持冷静的头脑和坚定的信念，才是成功的基石。</p>
<p>由于是第一届大会，当然也出现了写不足的地方。比较明显的，也是很多技术大会中遇到的问题，就是由于演讲者机会都是技术人员，而且有些可能是第一次面对这么多人演讲，难免有些紧张，导致表达的效果不够理想。而主办方可能是由于时间过于仓促，有些地方也不够周到。场地小，座位太少，话筒经常失灵，投影不清楚等也给大会的效果带来了少许影响。当然，瑕不掩瑜，相信这些问题在以后的大会中，都会有所改善。</p>
<p>本次大会的所有演讲稿都已经放出，请<a href="http://www.cocoachina.com/bbs/read.php?tid-8087.html" target="_blank" title="http://www.cocoachina.com/bbs/read.php?tid-8087.html">猛击这里</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.linsheng.me/archives/24.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>第一次</title>
		<link>http://blog.linsheng.me/archives/23.html</link>
		<comments>http://blog.linsheng.me/archives/23.html#comments</comments>
		<pubDate>Mon, 07 Sep 2009 10:45:25 +0000</pubDate>
		<dc:creator>林胜</dc:creator>
		
		<category><![CDATA[啰啰嗦嗦]]></category>

		<guid isPermaLink="false">http://blog.linsheng.me/?p=23</guid>
		<description><![CDATA[第一次因为开会迟到被罚款。不过好在罚款的方式很有创意，值得借鉴。
周五公司开管理会，大批人迟到，大家鱼贯而入，我最后一个。周六收到老板Email，出台罚款结果。第一个迟到的10元，第二个20，第三个40&#8230; 我是第7个，640。看到这个结果，我吓了一身冷汗。不是因为数目大，而且被计算方式的创新惊呆了。心中一个劲的后怕，多亏是乘以2，要是乘以10，我就要去卖身了&#8230;
PS: 看来真的上年纪了，和蚂蚁来来回回算了好几次才算出是第7个。
]]></description>
			<content:encoded><![CDATA[<p>第一次因为开会迟到被罚款。不过好在罚款的方式很有创意，值得借鉴。</p>
<p>周五公司开管理会，大批人迟到，大家鱼贯而入，我最后一个。周六收到老板Email，出台罚款结果。第一个迟到的10元，第二个20，第三个40&#8230; 我是第7个，640。看到这个结果，我吓了一身冷汗。不是因为数目大，而且被计算方式的创新惊呆了。心中一个劲的后怕，多亏是乘以2，要是乘以10，我就要去卖身了&#8230;</p>
<p>PS: 看来真的上年纪了，和蚂蚁来来回回算了好几次才算出是第7个。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.linsheng.me/archives/23.html/feed</wfw:commentRss>
		</item>
	</channel>
</rss>

