使用Karrigell开发是很简单的:
- 分发包自带一些强大的东西:一个web服务器和一个数据库引擎,整个包的大小不到1MB
- 不需要配置:只需解压包,运行服务器然后写代码即可
- 程序可以是纯Python代码也可以是Python与HTML混合就像PHP一样;它没有模板语法,需要学习自定义标签
print "Hello, world !"
但是如果你看过它的文档,你可能会对这个玩具能做的事感到惊讶:
-
简单的访问 HTML 表单
-
可以在一个脚本内包含其它脚本
-
非常简单的基于内存的 session 管理
-
基本的 HTTP 身份验证
-
HTTP 重定向
-
保护文件夹
-
多语言版本的动态页面
-
多样的编程方式,从把一个站点放在一个纯 Python 脚本中到像 PHP 一样一个脚本是一个页面的方式
-
内含 Cheetah 模板系统
-
自带一个非常快的异步 web 服务器
-
支持虚拟主机
-
支持 gzip
-
可以在 Apache 或 Xitami 下运行
-
带有一个简洁和完整的调试器
-
带有一个数据库管理系统
更多的信息参见documentation
1. Getting started
>python Karrigell.py
使用一个文本编辑器保存如下Python代码到webapps目录hello.py的文件里:
print "hello world !"
然后在web浏览器里键入http://localhost/hello.py查看结果
默认的,Python脚本被渲染成HTML代码。如果想使用纯文本格式可在代码里设置Content-Type头,就像这样:
RESPONSE['Content-Type'] = 'text/plain'
print "hello world !"
这个例子展示Karrigell如何工作的:脚本都运行在一个命名空间内。RESPONSE是这个命名空间里可用的名字,它是一个字典控制着HTTP响应的头。
2. HTML forms
让我们来看看在提交了一个HTML窗体后如何得到这些信息。新建这些HTML代码片段并保存在hello.htm中
<form action="hello.py">
Say hello to <input name="user">
<input type="submit" value="Ok">
</form>
这个页面显示用户名,并且可以提交到hello.py脚本
这是如何让hello.py打印信息的脚本:
print "Hello, " + _user
内置的Karrigell名字空间在接受到自浏览器发送的数据后会有一个叫_user的变量,它是输入到user字段的字符串值(注意是以下划线开头的,它用来避免与Python的关键字或内置的名字冲突)。
也可以选择使用这样的语法:
print "Hello, " + QUERY['user']
QUERY是一个提交表单的字段名字的字典
3. Logging and session management
如果想在一个站点里标识一个用户,比如需要打印它的名字,最简单的技巧是session管理。Karrigell使用另一个内置的名字一个叫Session()的函数来管理session,它返回一个可以设置任何属性的Python对象。
编辑脚本hello.py :
print "Hello, " + _user
Session().user = _user
print """What would you like to order :
<form action="order.py">
CD <input type="radio" name="type" value="CD">
book <input type="radio" name="type" value="book">
<input type="submit" value="Ok">
</form>"""
在第二行设置session对象的user属性值为_user。Session对象是web浏览器特有的,因此它能保证和持久一个用户可以被其它脚本标识。
例如可以在order.py中使用:
print "Hello %s" %Session().user
print "So you want to order a %s" %_type
4. Authentication
身份认证是一个非常常见的任务用来检查一个用户是否有执行一个任务的权限。因此,要求用户需要输入登录名和密码,程序会在数据库里查看登录名/密码是否合法。
改变HTML页面来要求输入一个用户名和密码而不只是一个用户名:
<form action="check.py">
Login <input name="login">
<br>Password <input type="password" name="password">
<input type="submit" value="Ok">
</form>
check.py脚本是这样的:
def is_valid(login,password):
# replace this with a check in the users database
return login == 'login' and password == 'password'
if is_valid(_login,_password):
Session().login = _login
print "Hello %s <br>" %_login
print """What would you like to order :
<form action="order.py">
CD <input type="radio" name="type" value="CD">
book <input type="radio" name="type" value="book">
<input type="submit" value="Ok">
</form>"""
else:
print "Sorry, you are not allowed to access this page"
Session对象有了一个login属性后,就可以在其他脚本里通过测试这个属性来测试用户的合法性了:
if hasattr(Session(),'login'):
(show information for authorized users)
else:
(show information for unlogged visitors)
当然也可以选择使用基本HTTP身份认证:一个要求输入登录名和密码的弹出式窗口。为了达到验证的目的在命名空间里一个叫Authentication()的函数,像这样使用:
def authTest():
(check if AUTH_USER and AUTH_PASSWORD are in the database)
Authentication(authTest,"Authentication test",/
"Sorry, you are not allowed to access this page")
print """What would you like to order :
<form action="order.py">
CD <input type="radio" name="type" value="CD">
book <input type="radio" name="type" value="book">
<input type="submit" value="Ok">
</form>"""
Authentication()带有3个参数:
- function:调用的函数,这个函数没有参数,但是它使用AUTH_USER和AUTH_PASSWORD它们是在弹出窗口输入的用户名和密码,如果验证成功将会继续执行下面的脚本
- realm:是一个显示在弹出窗口上的字符串
- message:当function没有返回True时,验证未成功时返回的信息。
如果验证成功将会继续执行下面的脚本。
5. Karrigell services
目前我们都是把脚本写在不同的文件里。但是一些比较小的脚本就会变的乏味和难以维护。
我们可以使用Karrigell services:Python脚本的每一个函数匹配一个URL。他必须使用“.ks”扩展名。
改变初始的HTML页面:
<form action="home.ks/check">
Login <input name="login">
<br>Password <input type="password" name="password">
<input type="submit" value="Ok">
</form>
然后在home.ks文件里保存下面的代码:
def check(login,password):
if _is_valid(login,password):
Session().login = login
print "Hello",login,"<br>"
print """What would you like to order :
<form action="order">
CD <input type="radio" name="Type" value="CD">
book <input type="radio" name="Type" value="book">
<input type="submit" value="Ok">
</form>"""
else:
print "Sorry, you are not allowed to access this page"
def order(Type):
if not hasattr(Session(),"login"):
print "Sorry, you are not allowed to access this page"
else:
print "Ok %s, you want to order a %s" %(Session().login,Type)
def _is_valid(login,password):
# replace this with a check in the users database
return login == 'login' and password == 'password'
HTML表单中的“action”值为“home.ks/check”,它的意思是Karrigell会在home.ks脚本里查找check()函数。表单里有字段“login”和“password”那么check函数里必须也有两个同名的参数。
在这个函数里,我们首先测试登录名和密码是否合法,它使用了一个私有的函数“_is_valid()”:“私有”的意思是不能通过URL(这里是home.ks/_is_valid)来访问这个函数。
如果测试成功,这个函数会输出另一个表单并且action为“order”,它匹配这个脚本里的order()函数。表单里有一个叫“Type”的字段,order()函数里同样也有一个叫Type的参数(注意Type是以大写字母开头的,这是为了与Python内置的type区别开来)
6. HTMLTags (generate HTML with Python code)
到现在为止我们都是在脚本中使用print语句把HTML标签包含在里面以用来处理HTML代码。
如果不喜欢这样,可以使用一个叫做HTMLTags的模块,它像这样:
from HTMLTags import *
print HTML(HEAD(TITLE('test'))+BODY('hello world'))
上面的代码与下面的HTML代码等同
<HTML>
<HEAD>
<TITLE>test</TITLE>
</HEAD>
<BODY>hello world</BODY>
</HTML>
可以像这样重写home.ks脚本:
from HTMLTags import *
def check(login,password):
if _is_valid(login,password):
Session().login = login
print "Hello",login,"<br>"
print """What would you like to order :"""
print FORM(TEXT('CD')+INPUT(Type="radio",name="Type",value="CD") +
TEXT('book')+INPUT(Type="radio",name="Type",value="book") +
INPUT(Type="submit",value="ok"),
action="order")
else:
print "Sorry, you are not allowed to access this page"
def order(Type):
if not hasattr(Session(),"login"):
print "Sorry, you are not allowed to access this page"
else:
print "Ok %s, you want to order a %s" %(Session().login,Type)
def _is_valid(login,password):
# replace this with a check in the users database
return login == 'login' and password == 'password'
7. Python Inside HTML (PHP-like style)
就像PHP那样把代码嵌入在特殊标签内,Karrigell提供“Python Inside HTML”。这样的脚本使用.pih扩展名,它在HTML代码中把Python代码写在<%和%>标签里。
回到我们的获得用户名的脚本示例里,我们把代码写在order.pih脚本里:
Hello, <% print _user
Session().user = _user %>
What would you like to order :
<form action="order.py">
CD <input type="radio" name="type" value="CD">
book <input type="radio" name="type" value="book">
<input type="submit" value="Ok">
</form>
没有严格的规则来选择编写Python脚本的方式,Karrigell services或Python Inside HTML。我趋向于:
-
Python Inside HTML
主要用于带有一些需要动态替换内容的静态
HTML
。
-
Karrigell services用于一些小程序,在10 or 20行的代码里创建每个页面都显示的结果
-
Python脚本用于处理数据然后发送到用户等更多的操作(通常地,如插入一个新的数据库记录)
8. Redirection
为了在一个脚本中实现HTTP重定向,需要触发一个在命名空间内可用的异常HTTP_REDIRECTION,它带有一个url参数。
raise HTTP_REDIRECTION,"index.html"
例如,如果要输入一个新记录到数据库,这是一个简单的ks脚本示例:
from HTMLTags import *
def index():
print FORM(TEXT('login')+INPUT(name="login")+BR()+
TEXT('password')+INPUT(name="password")+BR()+
INPUT(Type="submit"),
action = "insert")
def insert(login,password):
(... perform insertion in the database here ...)
raise HTTP_REDIRECTION,"index"
在插入完成后,程序将会访问另外一个接口。