web.py 学习笔记,web.py,web.py学习笔记 (
web.py 学习笔记,web.py,web.py学习笔记 (
web.py学习笔记 (一)
写在前面:
前段时间打算和一个朋友做一个网站,后来另一个罗马尼亚朋友加入做开发,但是因为种种原因又退出了。我们俩人的编程能力都很弱,几个月了网站还是停留在草图阶段。
之前主要在Google app engine上玩,但是限制太多,所以一直想自己用Django做点东西。折腾过一段时间的Pinax(因为听说这个做东西比较快),后来还是卡在后端编程上,没开发完成。
现在我们决定用web.py来做这个网站。这两天照着 http://webpy.org 的上的文档写了一下,觉得比Django简单些。
另外还参考了 http://wiki.woodpecker.org.cn/moin/WebPyCssFile
感觉web.py的文档资料比较少,没有Django那么完善,也没有比较成熟的开源案例可以学习,只能自己摸索着来。
学习中遇到的问题:
在webpy.org和其他很多关于web.py的tutorial中,有这么一段:
CREATE TABLE todo ( id serial primary key, title text, created timestamp default now(), done boolean default 'f' );
这是一段创建数据表的sql语句,当时我在phpmyadmin里怎么执行都不成功,后来问了以前的同事,才知道 done boolean default ‘f’ 已经不支持了,应该是 done boolean default ’0′ ,可能是我mysql版本的问题。
2.按照 http://wiki.woodpecker.org.cn/moin/WebPyCssFile 写完之后,访问页面发现报错:
<type 'exceptions.SyntaxError'> at /invalid syntax Template traceback: File 'templates/index.html', line 13<h1>CSS Test</h1>(index.html, line 13) Python /Library/Python/2.7/site-packages/web.py-0.37-py2.7.egg/web/template.py in compile_template, line 911 Web GET http://0.0.0.0:8080/
google查了很久没搜到结果,后来给文章作者发邮件询问是不是我的web.py版本问题?结果没等他回信,我就自己解决了。我先尝试把所有的tab缩进改成空格缩进,无果,然后又把所有的空格缩进改成tab缩进,还是无果,后来把.py文件头部的
#!/usr/bin/env python# coding: utf-8
挨个删掉,每删一个就看看是不是正常了,结果全删完了报错了,说什么编码有问题,然后又一个个往回加,调着调着就行了。
现在的目录结构:
好了,现在怎么让页面呈现出来已经搞定,接下来准备着手写用户注册页面。
这时候又遇到一个棘手的问题,mysql里怎么建用户表?什么int、varchar我都不知道有什么区别,以前没有这方面的经验,都是其他同事做。在网上找了找资料,大概建成了这样:
接下来遇到的问题就是如何对数据进行增删改查,这方面更没有经验,等天亮之后问问同事看。
总结:
web.py的开发速度比Django快多了,之前看Djando的文档,一直卡在模版处理那一块儿,web.py的模版处理对我来说相对简单一些,听说还可以结合mako模版引擎来处理,但我决定暂时不用,先用最原始的办法解决问题。
最终的效果(未加CSS样式):
web.py学习笔记 (二)
今天在同事的帮助下完成了mysql用户表的创建,还不是很好。
同事给的比较好的用户表是这么建的:
CREATE TABLE IF NOT EXISTS `xch_account` ( `id` mediumint(8) unsigned NOT NULL auto_increment, `email` varchar(100) NOT NULL default '', `password` char(32) NOT NULL default '', `firstname` varchar(50) NOT NULL default '', `lastname` varchar(50) NOT NULL default '', `city` varchar(50) NOT NULL default '', `address` varchar(200) NOT NULL default '', `tel` varchar(100) NOT NULL default '', `mobile` varchar(100) NOT NULL default '', `postcode` varchar(100) NOT NULL default '', `qq` varchar(100) NOT NULL default '', `regip` varchar(15) NOT NULL default '', `lastip` varchar(15) NOT NULL default '', `regtime` int(10) unsigned NOT NULL default '0', `lasttime` int(10) unsigned NOT NULL default '0', `loginnum` smallint(5) unsigned NOT NULL default '0', `ukey` char(32) NOT NULL default '', `lev` tinyint(1) unsigned NOT NULL default '0' COMMENT '0=>普通用户 1=>VIP用户', `discount` decimal(2,1) unsigned NOT NULL default '1.0', `verify` tinyint(1) unsigned NOT NULL default '0', `auto` tinyint(1) unsigned NOT NULL default '0' COMMENT '自动出单', PRIMARY KEY (`id`), UNIQUE KEY `email` (`email`), UNIQUE KEY `ukey` (`ukey`), KEY `regtime` (`regtime`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
我的表结构现在是这样:
不管怎么说,反正能用了。今天还做了注册页面、登录页面和登录成功后的欢迎页面,然后就开始写用户注册时的数据存储。
class SignupHandler: def GET(self): # do $:f.render() in the template f = register_form() return render.signup(f) def POST(self): f = register_form() name = web.input(name = "username") pwd = web.input(name = "password") if not f.validates(): return render.signup(f) else: sequence_id = db.insert('userAuth', username = name, password = pwd, joindate = web.SQLLiteral("NOW()"), ipaddress = "111.1.1.1", lastactivity = web.SQLLiteral("NOW()")) raise web.seeother('/welcome')
悲催的是发现这么写数据库里存的数据都不正常:
后来在V2EX上发帖求教,同时自己找问题解决办法,结果V2EX上还没等人回应,我自己就找到错误原因了。原来需要把
name = web.input(name = "username")pwd = web.input(name = "password")
改成:
name = web.input().usernamepwd = web.input().password
这样数据库里存储的文本就正常了。
web.py学习笔记 – 03
鉴于整个用户模块比较复杂,我找到了一个开源的web.py站点“MLSS”来做参考,打算以此为基础进行改进。
MLSS中跟user相关的主要文件有controllers部分的 /app/controllers/account.py 和model部分的 /app/models/users.py 以及view部分的 /app/views/account.html。我的理解,user主要的功能有登录 / 注册 / 找回密码 / 退出,在MLSS中,分别对应了 /app/controllers/account.py中的 login / register / resend_password / logout。
在测试过程中发现MLSS的用户密码没有加密,比如用户注册时填写的密码是“111111”,保存到数据库中还是“111111”,感觉好坑爹!不行,这个得改!于是我着手给密码进行加密。
我感觉应该是在 model 部分的 /app/models/users.py 中做入库之前的加密,找到一看,发现坑爹的代码:
def create_account(email, password, nickname): db.insert('users', email=email, password=password, nickname=nickname)
直接就 password=password
了!于是我就改成了:
password=hashlib.md5(password + encryption_key).hexdigest()
这段加密的代码也是我从cookbook上找来的。原代码是:
pwdhash = hashlib.md5(i.password).hexdigest()
稍微变通一下就可以啦。
encryption_key 是 一串密钥,在 config.py 中。
# used as a saltencryption_key = 'a random string'
这样对密码进行之后,登录那边的验证也要跟着改:
def is_correct_password(email, password): user = get_user_by_email(email) return user.get('password', False) == password
改为了:
def is_correct_password(email, password): user = get_user_by_email(email) pwdhash = hashlib.md5(password + encryption_key).hexdigest() #密码混合密钥进行md5加密 return user.get('password', False) == pwdhash #判断密码是否正确
这样就完成啦,不过我还是觉得不太满意,用户的IP地址还没有呢,于是我又琢磨怎么得到用户的IP地址,google之后看到 cookbook 中有讲用 web.ctx获得IP,但是我以为是这么写:
ip = web.ctx.ip.get('HTTP_REFERER')
或者是:
ip = web.ctx.ip.get()
结果发现都不对,后来在“blog-with-gae”中有了发现,原来应该是这样:
ip = web.ctx.ip
OK,又搞定了一个。
接下来我想做用户的找回密码功能,因为MLSS的找回密码也很坑爹,直接把密码发到邮箱里了:
#-------/app/controllers/account.py------ user = users.get_user_by_email(f.d.email) email_templates.resend_password(user) return render_account(show, on_success_message='Login information succesfully emailed.')#---------------------#-------/app/helps/email_templates.py------msg_forgot = \'''$def with (user)Hello $user.nickname, Here are the login information you have requested:login: $user.emailpassword: $user.passwordThank you,'''#---------------------
咨询了以前的同事,他说用户需要一个唯一的key,然后用这个key组合成重置密码的url发给用户,还需要给url设置过期时间。
一步步来:先做key。我想的是用10位随机数 + 时间 + 用户邮箱地址 + 站点密钥 进行加密作为key。代码如下:
#-------/app/models/user.py------- #生成10位随机数 all = list('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSQUVWXYZ') randStr = '' for i in range(10): index = random.randint(0,len(all)) randStr = randStr + all[index] currTime = time.strftime('%Y%m%d%H%I%M%S',time.localtime(time.time())) #加密:随机数 + 时间 + 邮箱地址 + 密钥. //authKey为找回密码用,每个用户都有一个唯一的authKey authKey = hashlib.md5(randStr + currTime + email + encryption_key).hexdigest()#---------------------
当时找生成随机数的方法找了好长时间(Python基础不行真是太费事了),最终注册部分的代码是这样:
#-------/app/models/user.py-------#!/usr/bin/env python# coding: utf-8import randomimport timeimport hashlibimport webimport socketfrom config import db , encryption_keydef create_account(email, password, nickname): #生成10位随机数 all = list('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSQUVWXYZ') randStr = '' for i in range(10): index = random.randint(0,len(all)) randStr = randStr + all[index] currTime = time.strftime('%Y%m%d%H%I%M%S',time.localtime(time.time())) #加密:随机数 + 时间 + 邮箱地址 + 密钥. //authKey为找回密码用,每个用户都有一个唯一的authKey authKey = hashlib.md5(randStr + currTime + email + encryption_key).hexdigest() #得到客户端IP地址 ipAddress = web.ctx.ip #入库 db.insert('users', email=email, password=hashlib.md5(password + encryption_key).hexdigest(), nickname=nickname, authKey = authKey, ipAddress = ipAddress)#注:password 为混合密钥进行md5加密
下面的登录退出部分就先省略了,另外,还修正了很长时间没有解决的一个Bug:
class Redirect:#Make url ending with or without '/' going to the same class. def GET(self, path): web.seeother('/' + path)
我始终不知道这段代码加在哪儿,就随手放config.py里了,后来发现没有起作用。刚才看“blog-with-gae”的代码,才发现原来需要在url设置中加上:
'/(.*)/', config.Redirect,
才可以啊!
总结
多看别人的代码可以学到很多东西!接下来要继续完善找回密码部分。
相关内容
- 使用nosetests对webpy程序做单元测试,nosetestswebpy,index.p
- python调用短信猫控件,发短信,python调用短信控件,我分
- webpy上传大文件代码,webpy上传文件代码,webpy上传普通文
- python里面向shell输出彩色字符串,pythonshell输出,shell里面
- python替换html中的空标签,python替换html标签,html中的空行
- 数独人工算法的python实现,人工算法python,目前只有两个
- python使用os.path和hashlib遍历目录计算所有文件的md5值,
- python过滤字符串中不属于指定集合的字符的类,python字
- python清空linux/unix系统共享内存代码,pythonunix,# -*- cod
- python使用蒙特卡洛方法计算圆周率,python蒙特卡洛,蒙特
评论关闭