Differences between revisions 2 and 3
Revision 2 as of 2008-09-24 13:18:16
Size: 3639
Editor: HuangYi
Comment:
Revision 3 as of 2008-09-24 16:22:09
Size: 9854
Editor: HuangYi
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
##language:zh
##OBP项目图书reST通用文章模板

||status|| 草稿 ||HuangYi; 30%||

[[TableOfContents]]

那么小白决定进一步探索 python web开发更高级一点的技术了,行者建议他从基础入手。

当用户在浏览器中输入网址,浏览器便找到web服务器,向它发起http请求,
web服务器再找到web应用程序执行之,并把结果返回给客户端浏览器。

那么做web开发之前首先要有web服务器才行,开发阶段最好使用一个简单方便的开发服务器。
等开发调试完毕,再将代码部署到 apache、lighttpd 等成熟高效的web服务器,
放心,使用python做web开发,最后部署的阶段是很轻松的,在本章的后面便会提到。
Line 3: Line 19:
wsgiref 提供一些 web 开发的基础功能最有用的就是提供了一个简单的开发服务器

{{{#!python
那么 python2.5 就自带了一个叫做 wsgiref 模块,它提供一些专业 web 开发所需要一些基础工具比如一个开发服务器

{{{#!python
# -*- coding: utf-8 -*-
Line 7: Line 24:

# 定义一个输出 hello world 和环境变量的简单web应用程序
Line 8: Line 27:
    # 输出 http 头
Line 9: Line 29:
    yield 'Hello world\n'     # 准备输出的内容
    content = []
    content.append('Hello world')
Line 11: Line 33:
        yield '%s : %s\n' % (key, value)
        content.append('%s : %s' % (key, value))
    # 输出,根据 wsgi 协议,返回的需要是一个迭代器,返回一个 list 就可以
    return ['\n'.join(content)]

# 构造开发服务器对象,设置绑定的地址和端口,并把 hello world 应用程序传给他
Line 14: Line 39:
# 启动开发服务器
Line 17: Line 43:
把以上代码以utf-8编码保存成python程序,不妨命名为 main.py。然后执行上面这个程序后,打开浏览器,访问 http://localhost:8000 即可看到输出的内容。

{{{注意::
  wsgiref 带的这个开发服务器调用应用程序所使用的协议叫做 wsgi,wsgiref就是对wsgi协议的
  一个参考实现,wsgi 协议内容可以参考:URL ,在这里你只需要知道,hello_app 的第一个参数environ
  是包含web环境变量的字典,类似于 cgi 的环境变量,里面包含了请求的URL,请求客户端的IP等信息。
  第二个参数 start_response 是一个函数,调用它来输出 http 状态码和响应头。
}}}
Line 19: Line 54:
mako 是一个模板引擎,通过将动态的数据填充到模板中,可以用来生成复杂的页面。

{{{#!python
from mako import Template
tmpl = Template('./simple.html')
print tmpl.render(data = {'a':1, 'b':2})
}}}

simple.html
但是 web程序大部分时候都是要返回一个 html 页面的,而把一个复杂的 html 页面
代码放到python代码里面就太丑陋了,应该把它放到一个模板里去,把页面展现与
业务逻辑分离开来。

python里面的模板引擎主要有mako、genshi、jinja等。mako 主要特点在于模板里面
可以比较方便的嵌入python代码,而且执行效率一流;genshi 的特点在于基于 xml,
非常简单易懂的模板语法,对于热爱xhtml的朋友来说是很好的选择,同时也可以嵌入python
代码,实现一些复杂的展现逻辑;jinja 和 genshi 一样拥有很简单的模板语法,只是不
依赖于 xml 的格式,同样很适合设计人员直接进行模板的制作,同时也可以嵌入python
代码实现一些复杂的展现逻辑。

小白看 mako 挺顺眼的,于是就钻研了它一把。
可以到这里 http://www.makotemplates.org/download.html 找到最新版本的下载地址,下载解压,
然后执行 python setup.py install 就可以了。

下面的代码就是写的一个简单的 mako 模板文件,里面使用 python 的 for 循环来把 data 这个字典的
内容填充到一个html列表(mako模板的详细语法请参考:URL)。
Line 36: Line 80:
      % for key, value in environ.items():       % for key, value in data.items():
Line 46: Line 90:
和 wsgiref 整合:

{{{#!python
然后要做的就是给模板传递一个叫做 data 的字典对象了,可以编写如下三句代码实现:

{{{#!python
# -*- coding: utf-8 -*-
# 导入模板对象
from mako import Template
# 使用模板文件名构造模板对象
tmpl = Template('./simple.html')
# 构造一个简单的字典填充模板,并print出来
print tmpl.render(data = {'a':1, 'b':2})
}}}

执行以上程序,就可以看到通过模板输出的 html 代码了。
现在再看看如何把它用到web应用中来吧。

{{{#!python
# -*- coding: utf-8 -*-
Line 51: Line 109:
Line 54: Line 113:
    start_response('200 OK', [('Content-type','text/plain')])     start_response('200 OK', [('Content-type','text/html')])
Line 61: Line 120:
执行这个程序,并访问 http://localhost:8000 你就可以看到通过模板输出的页面了。
Line 63: Line 124:
sqlalchemy 是一个 ORM,提供python对象与关系数据库之间的映射,通过 python 对象,
对关系数据库进行操纵。

model.py
{{{#!python
作为一个动态网站,有很多数据需要持久存储,关系数据库在这方面通常都是不二选择。
当小白向行者问道如何才能简化对数据库的访问时,行者郑重向小白推荐了 sqlalchemy 这个库。

sqlalchemy 是一个 ORM (对象-关系映射)库,提供python对象与关系数据库之间的映射,
可以通过 python 对象很方便地对关系数据库进行操纵,比如使用python代码描述数据库结构,
创建数据库,执行插入、查询、删除等数据库操作,非常方便。除了这些 ORM 的基本功能外,
sqlalchemy 还支持Model的继承,自引用(Self-referential)、eager loading、lazy loading 等等,
还可以直接将 Model 映射到自定义的 SQL 语句。可以说既有不输于 Hibernate 的强大功能,
同时不失 Python 的优雅简洁。

在这里 http://www.sqlalchemy.org/download.html 找到最新版本的下载地址,下载解压,
然后执行 python setup.py install 进行安装。

代码胜千言,sqlalchemy 到底可以做什么,直接上代码展示下 sqlalchemy 的基本功能吧:

{{{#!python
# -*- coding: utf-8 -*-
from sqlalchemy.ext.declarative import declarative_base

# 创建数据库引擎,这里我们直接使用 python2.5 自带的数据库引擎:sqlite,
# 直接在当前目录下建立名为 data.db 的数据库
engine = create_engine('sqlite:///data.db')
# sqlalchemy 中所有数据库操作都要由某个session来进行管理
# 关于 session 的详细信息请参考:http://www.sqlalchemy.org/docs/05/session.html
Session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base = declarative_base()

class Dictionay(Base):
    # python 对象对应关系数据库的表名
    __tablename__ = 't_dictionay'
    # 两个字段:
    key = Column('key', String(255), primary_key=True)
    value = Column('value', String(255))

# 创建数据库
Base.metadata.create_all(engine)

session = Session()
for item in ['python','ruby','java']:
    dictionay = Dictionay(key=item, value=item.upper())
    session.add(dictionay)

# 提交session,在这里才真正执行数据库的操作,添加三条记录到数据库
session.commit()

# 查询Dictionary类对应的数据
for dictionay in session.query(Dictionary):
    print dictionay.name, dictionay.value
}}}

直接执行这个程序就可以了。
不过这是个单独的 demo,要把放到 web 应用里面,还需要先对它的结构重新组织一下。

先剥离出一个公用的 model.py 文件。

{{{#!python
# -*- coding: utf-8 -*-
Line 78: Line 191:

# 创建数据库
Base.metadata.create_all(engine)

session = Session()
for item in ['python','ruby','java']:
    dictionay = Dictionay(key=item, value=item.upper())
    session.add(dictionay)

session.commit()

for dictionay in session.query(Dictionary):
    print dictionay.name, dictionay.value
}}}

上面是个 demo,下面我们把它分解,并放到web应用中去。

model.py
{{{#!python
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///data.db')
Session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
Base = declarative_base()

class Dictionay(Base):
    __tablename__ = 't_dictionay'
    key = Column('key', String(255), primary_key=True)
    value = Column('value', String(255))
}}}

create_db.py
{{{#!python
}}}

然后建立一个创建数据库并插入一些测试数据的单独的程序,创建数据库只需要一开始做一次就可以了。

{{{#!python
# -*- coding: utf-8 -*-
# 导入公用的 model 模块
Line 125: Line 212:
和 wsgiref 整合
{{{#!python
最后再将这个功能加入到我们的 web 程序里面来:

{{{#!python
# -*- coding: utf-8 -*-
Line 129: Line 218:
# 导入公用的 model 模块
Line 132: Line 222:
    # 查询到所有 Dictionary 对象
Line 133: Line 224:
    # 然后根据 Dictionary 对象的 name、value 属性把列表转换成一个字典
Line 135: Line 227:
    # 填充模板
Line 144: Line 237:

执行上面这个文件并打开浏览器访问 http://localhost:8000/ 就可以看到刚才创建的三条测试数据了。

== yaro ==
TODO 引入一个request、response对象的实现
http://lukearno.com/projects/yaro/

== beaker ==
TODO 引入 session 的实现:beaker
http://beaker.groovie.org/

TODO 其他组件的介绍

现在让我们回头看一下,我们最终得到了一个什么样的程序。

TODO 成熟 web 框架介绍

status

草稿

HuangYi; 30%

TableOfContents

那么小白决定进一步探索 python web开发更高级一点的技术了,行者建议他从基础入手。

当用户在浏览器中输入网址,浏览器便找到web服务器,向它发起http请求, web服务器再找到web应用程序执行之,并把结果返回给客户端浏览器。

那么做web开发之前首先要有web服务器才行,开发阶段最好使用一个简单方便的开发服务器。 等开发调试完毕,再将代码部署到 apache、lighttpd 等成熟高效的web服务器, 放心,使用python做web开发,最后部署的阶段是很轻松的,在本章的后面便会提到。

wsgiref

那么 python2.5 就自带了一个叫做 wsgiref 模块,它提供一些专业 web 开发所需要的一些基础工具,比如一个开发服务器:

   1 # -*- coding: utf-8 -*-
   2 import wsgiref
   3 
   4 # 定义一个输出 hello world 和环境变量的简单web应用程序
   5 def hello_app(environ, start_response):
   6     # 输出 http 头
   7     start_response('200 OK', [('Content-type','text/plain')])
   8     # 准备输出的内容
   9     content = []
  10     content.append('Hello world')
  11     for key, value in environ.items():
  12         content.append('%s : %s' % (key, value))
  13     # 输出,根据 wsgi 协议,返回的需要是一个迭代器,返回一个 list 就可以
  14     return ['\n'.join(content)]
  15 
  16 # 构造开发服务器对象,设置绑定的地址和端口,并把 hello world 应用程序传给他
  17 server = wsgiref.make_server('localhost', 8000, hello_app)
  18 # 启动开发服务器
  19 server.serve_forever()

把以上代码以utf-8编码保存成python程序,不妨命名为 main.py。然后执行上面这个程序后,打开浏览器,访问 http://localhost:8000 即可看到输出的内容。

{{{注意::

  • wsgiref 带的这个开发服务器调用应用程序所使用的协议叫做 wsgi,wsgiref就是对wsgi协议的 一个参考实现,wsgi 协议内容可以参考:URL ,在这里你只需要知道,hello_app 的第一个参数environ 是包含web环境变量的字典,类似于 cgi 的环境变量,里面包含了请求的URL,请求客户端的IP等信息。 第二个参数 start_response 是一个函数,调用它来输出 http 状态码和响应头。

}}}

mako

但是 web程序大部分时候都是要返回一个 html 页面的,而把一个复杂的 html 页面 代码放到python代码里面就太丑陋了,应该把它放到一个模板里去,把页面展现与 业务逻辑分离开来。

python里面的模板引擎主要有mako、genshi、jinja等。mako 主要特点在于模板里面 可以比较方便的嵌入python代码,而且执行效率一流;genshi 的特点在于基于 xml, 非常简单易懂的模板语法,对于热爱xhtml的朋友来说是很好的选择,同时也可以嵌入python 代码,实现一些复杂的展现逻辑;jinja 和 genshi 一样拥有很简单的模板语法,只是不 依赖于 xml 的格式,同样很适合设计人员直接进行模板的制作,同时也可以嵌入python 代码实现一些复杂的展现逻辑。

小白看 mako 挺顺眼的,于是就钻研了它一把。 可以到这里 http://www.makotemplates.org/download.html 找到最新版本的下载地址,下载解压, 然后执行 python setup.py install 就可以了。

下面的代码就是写的一个简单的 mako 模板文件,里面使用 python 的 for 循环来把 data 这个字典的 内容填充到一个html列表(mako模板的详细语法请参考:URL)。

<html>
  <head>
    <title>简单mako模板</title>
  </head>
  <body>
    <h5>Hello World!</h5>
    <ul>
      % for key, value in data.items():
      <li>
        ${key} - ${value}
      <li>
      % endfor
    </ul>
  </body>
</html>

然后要做的就是给模板传递一个叫做 data 的字典对象了,可以编写如下三句代码实现:

   1 # -*- coding: utf-8 -*-
   2 # 导入模板对象
   3 from mako import Template
   4 # 使用模板文件名构造模板对象
   5 tmpl = Template('./simple.html')
   6 # 构造一个简单的字典填充模板,并print出来
   7 print tmpl.render(data = {'a':1, 'b':2})

执行以上程序,就可以看到通过模板输出的 html 代码了。 现在再看看如何把它用到web应用中来吧。

   1 # -*- coding: utf-8 -*-
   2 import wsgiref
   3 from mako import Template
   4 
   5 def hello_app(environ, start_response):
   6     tmpl = Template('./simple.html')
   7     content = tmpl.render(data=environ)
   8     start_response('200 OK', [('Content-type','text/html')])
   9     return [content]
  10 
  11 server = wsgiref.make_server('localhost', 8000, hello_app)
  12 server.serve_forever()

执行这个程序,并访问 http://localhost:8000 你就可以看到通过模板输出的页面了。

sqlalchemy

作为一个动态网站,有很多数据需要持久存储,关系数据库在这方面通常都是不二选择。 当小白向行者问道如何才能简化对数据库的访问时,行者郑重向小白推荐了 sqlalchemy 这个库。

sqlalchemy 是一个 ORM (对象-关系映射)库,提供python对象与关系数据库之间的映射, 可以通过 python 对象很方便地对关系数据库进行操纵,比如使用python代码描述数据库结构, 创建数据库,执行插入、查询、删除等数据库操作,非常方便。除了这些 ORM 的基本功能外, sqlalchemy 还支持Model的继承,自引用(Self-referential)、eager loading、lazy loading 等等, 还可以直接将 Model 映射到自定义的 SQL 语句。可以说既有不输于 Hibernate 的强大功能, 同时不失 Python 的优雅简洁。

在这里 http://www.sqlalchemy.org/download.html 找到最新版本的下载地址,下载解压, 然后执行 python setup.py install 进行安装。

代码胜千言,sqlalchemy 到底可以做什么,直接上代码展示下 sqlalchemy 的基本功能吧:

   1 # -*- coding: utf-8 -*-
   2 from sqlalchemy.ext.declarative import declarative_base
   3 
   4 # 创建数据库引擎,这里我们直接使用 python2.5 自带的数据库引擎:sqlite,
   5 # 直接在当前目录下建立名为 data.db 的数据库
   6 engine = create_engine('sqlite:///data.db')
   7 # sqlalchemy 中所有数据库操作都要由某个session来进行管理
   8 # 关于 session 的详细信息请参考:http://www.sqlalchemy.org/docs/05/session.html
   9 Session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
  10 Base = declarative_base()
  11 
  12 class Dictionay(Base):
  13     # python 对象对应关系数据库的表名
  14     __tablename__ = 't_dictionay'
  15     # 两个字段:
  16     key = Column('key', String(255), primary_key=True)
  17     value =  Column('value', String(255))
  18 
  19 # 创建数据库
  20 Base.metadata.create_all(engine)
  21 
  22 session = Session()
  23 for item in ['python','ruby','java']:
  24     dictionay = Dictionay(key=item, value=item.upper())
  25     session.add(dictionay)
  26 
  27 # 提交session,在这里才真正执行数据库的操作,添加三条记录到数据库
  28 session.commit()
  29 
  30 # 查询Dictionary类对应的数据
  31 for dictionay in session.query(Dictionary):
  32     print dictionay.name, dictionay.value

直接执行这个程序就可以了。 不过这是个单独的 demo,要把放到 web 应用里面,还需要先对它的结构重新组织一下。

先剥离出一个公用的 model.py 文件。

   1 # -*- coding: utf-8 -*-
   2 from sqlalchemy.ext.declarative import declarative_base
   3 
   4 engine = create_engine('sqlite:///data.db')
   5 Session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
   6 Base = declarative_base()
   7 
   8 class Dictionay(Base):
   9     __tablename__ = 't_dictionay'
  10     key = Column('key', String(255), primary_key=True)
  11     value =  Column('value', String(255))

然后建立一个创建数据库并插入一些测试数据的单独的程序,创建数据库只需要一开始做一次就可以了。

   1 # -*- coding: utf-8 -*-
   2 # 导入公用的 model 模块
   3 from model import Base, Session, Dictionary
   4 
   5 # 创建数据库
   6 Base.metadata.create_all(engine)
   7 
   8 # 插入初始数据
   9 session = Session()
  10 for item in ['python','ruby','java']:
  11     dictionay = Dictionay(key=item, value=item.upper())
  12     session.add(dictionay)
  13 
  14 session.commit()

最后再将这个功能加入到我们的 web 程序里面来:

   1 # -*- coding: utf-8 -*-
   2 import wsgiref
   3 from mako import Template
   4 # 导入公用的 model 模块
   5 from model import Session, Dictionary
   6 def hello_app(environ, start_response):
   7     session = Session()
   8     # 查询到所有 Dictionary 对象
   9     dictionaries = session.Query(Dictionary)
  10     # 然后根据 Dictionary 对象的 name、value 属性把列表转换成一个字典
  11     data = dict([(dictionary.name, dictionary.value) for dictionary in dictionaries])
  12 
  13     # 填充模板
  14     tmpl = Template('./simple.html')
  15     content = tmpl.render(data=data)
  16 
  17     start_response('200 OK', [('Content-type','text/plain')])
  18     return [content]
  19 
  20 server = wsgiref.make_server('localhost', 8000, hello_app)
  21 server.serve_forever()

执行上面这个文件并打开浏览器访问 http://localhost:8000/ 就可以看到刚才创建的三条测试数据了。

yaro

TODO 引入一个request、response对象的实现 http://lukearno.com/projects/yaro/

beaker

TODO 引入 session 的实现:beaker http://beaker.groovie.org/

TODO 其他组件的介绍

现在让我们回头看一下,我们最终得到了一个什么样的程序。

TODO 成熟 web 框架介绍

ObpLovelyPython/AbtWebModules (last edited 2009-12-25 07:15:55 by localhost)