一、python实现web服务器
web开发首先要有web服务器才行。比如apache,但是在开发阶段最好有一个简单方便的开发服务器,容易重启进行调试,等开发调试完毕后,再将代码部署到成熟稳定高效的web服务器。
# -*- coding: utf-8 -*-
from wsgiref import simple_server
# 定义一个输出 hello world 和环境变量的简单web应用程序
def hello_app(environ, start_response):
# 输出 http 头,text/plain 表示是纯文本
start_response(‘200 ok’, [(‘content-type’,’text/plain’)])
# 准备输出的内容
content = []
content.append(‘hello world’)
for key, value in environ.items():
content.append(‘%s : %s’ % (key, value))
# 输出,根据 wsgi 协议,返回的需要是一个迭代器,返回一个 list 就可以
return [‘\n’.join(content)]
# 构造开发服务器对象,设置绑定的地址和端口,并把 hello world 应用程序传给他
server = simple_server.make_server(‘localhost’, 8080, hello_app)
# 启动开发服务器
server.serve_forever()
执行上面这个程序后,打开浏览器,访问一个以 #:8080 开头的网址即可看到 environ 所包含的内容。
# -*- coding: utf-8 -*-
from wsgiref import simple_server
from webob import request, response
# 我们顺便增加了一个功能,就是根据用户在 url 后面传递的参数
# 显示相应的内容
def hello_app(request):
content = []
# 获取 get 请求的参数
content.append(‘hello %s’%request.get[‘name’])
# 输出所有 environ 变量
for key, value in request.environ.items():
content.append(‘%s : %s’ % (key, value))
response = response(body=’\n’.join(content))
response.headers[‘content-type’] = ‘text/plain’
return response
# 对请求和响应进行包装
def wsgi_wrapper(environ, start_response):
request = request(environ)
response = hello_app(request)
# response 对象本身也实现了与 wsgi 服务器之间通讯的协议,
# 所以可以帮我们处理与web服务器之间的交互。
# 这一句比较奇怪,对象使用括号是什么意思。。。。
return response(environ, start_response)
server = simple_server.make_server(‘localhost’, 8080, wsgi_wrapper)
server.serve_forever()
为了让 wsgi_wrapper 更加通用一点,可以把它设计成装饰器的形式:
# -*- coding: utf-8 -*-
from wsgiref import simple_server
from webob import request, response
# 写成装饰器的 wsgi_wrapper
def wsgi_wrapper(func):
def new_func(environ, start_response):
request = request(environ)
response = func(request)
return response(environ, start_response)
new_func.__name__ = func.__name__
new_func.__doc__ = func.__doc__
return new_func
# 应用程序
@wsgi_wrapper
def hello_app(request):
content = []
content.append(‘hello %s’%request.get[‘name’])
for key, value in request.environ.items():
content.append(‘%s : %s’ % (key, value))
response = response(body=’\n’.join(content))
response.headers[‘content-type’] = ‘text/plain’
return response
server = simple_server.make_server(‘localhost’, 8080, hello_app)
server.serve_forever()
三、模板果然,还是需要用到模板,不能总是直接在response中写上长串的html代码。python中的模板引擎主要有mako, genshi, jinjia等。mako 主要特点在于模板里面 可以比较方便的嵌入python代码,而且执行效率一流;genshi 的特点在于基于 xml, 非常简单易懂的模板语法,对于热爱xhtml的朋友来说是很好的选择,同时也可以嵌入python 代码,实现一些复杂的展现逻辑;jinja 和genshi 一样拥有很简单的模板语法,只是不 依赖于 xml 的格式,同样很适合设计人员直接进行模板的制作,同时也可以嵌入python 代码实现一些复杂的展现逻辑。
这里使用mako,地址ttp://pypi.python.org/pypi/mako,下载python setup.py install进行安装简单的模块例子:
## -*- coding: utf-8 -*-
简单mako模板
hello ${name}!
% for key, value in data.items():
${key} – ${value}
% endfor
保存为simple.html文件,然后需要给模板对象传递data和name两个参数,然后进行渲染,就可以输入html内容
# -*- coding: utf-8 -*-
# 导入模板对象
from mako.template import template
# 使用模板文件名构造模板对象
tmpl = template(filename=’./simple.html’, output_encoding=’utf-8′)
# 构造一个简单的字典填充模板,并print出来
print tmpl.render(name=’python’, data = {‘a’:1, ‘b’:2})
保存为test_template.py文件,运行就可以输入内容:$ python test_template.py
简单mako模板
hello python!
a – 1
b – 2
下面对hello_app程序进行重构:1. 把 wsgi_wrapper 单独放到通用模块 utils.py:
# -*- coding: utf-8 -*-
from webob import request
def wsgi_wrapper(func):
def new_func(environ, start_response):
request = request(environ)
response = func(request)
return response(environ, start_response)
new_func.__name__ = func.__name__
new_func.__doc__ = func.__doc__
return new_func
2. 把 hello_app 给彻底独立出来,形成单独的模块 controller.py :
# -*- coding: utf-8 -*-
from utils import wsgi_wrapper
from webob import response
from mako import template
# 整合了模板功能的 hello_app
@wsgi_wrapper
def hello_app(request):
tmpl = template(filename=’./simple.html’, output_encoding=’utf-8′)
content = tmpl.render(name=request.get[‘name’], data=request.environ)
return response(body=content)
3. 这样 main.py 就变成这样了:
# -*- coding: utf-8 -*-
from wsgiref import simple_server
from controller import hello_app
server = simple_server.make_server(‘localhost’, 8080, hello_app)
server.serve_forever()
四、orm(object relation mapping, 对象关系映射)终于也要这一步了,作为web应用,还是需要与数据库进行合作。这里使用sqlalchemy,是一个 orm (对象-关系映射)库,提供python对象与关系数据库之间的映射。和django的models用法很像,也是可以通过python代码来创建数据库表,并进行操作。sqlalchemy 还可以自动映射 python 对象的继承,可以实现eager loading、lazy loading, 可以直接将 model 映射到自定义的 sql 语句,支持n多的数据库等等等等。 可以说 sqlalchemy 既有不输于 hibernate 的强大功能,同时不失 python的简洁优雅。使用方法:
# -*- coding: utf-8 -*-
from sqlalchemy import *
from sqlalchemy.orm import sessionmaker, scoped_session
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 dictionary(base):
# python 对象对应关系数据库的表名
__tablename__ = ‘t_dictionary’
# 定义自动,参数含义分别为:数据库字段名,字段类型,其他选项
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’]:
# 构造一个对象
dictionary = dictionary(key=item, value=item.upper())
# 告诉 sqlalchemy ,将该对象加到数据库
session.add(dictionary)
# 提交session,在这里才真正执行数据库的操作,添加三条记录到数据库
session.commit()
# 查询数据库中dictionary对象对应的数据
for dictionary in session.query(dictionary):
print dictionary.key, dictionary.value
上面的代码你执行两遍就会报错,为什么。。。因为插入数据库的主键重复了。。。。 这样就可以整合到之前的controller.py文件中
# -*- coding: utf-8 -*-
from utils import wsgi_wrapper
from webob import response
from mako.template import template
# 导入公用的 model 模块
from model import session, dictionary
@wsgi_wrapper
def hello_app(request):
session = session()
# 查询到所有 dictionary 对象
dictionaries = session.query(dictionary)
# 然后根据 dictionary 对象的 key、value 属性把列表转换成一个字典
data = dict([(dictionary.key, dictionary.value) for dictionary in dictionaries])
tmpl = template(filename=’./simple.html’, output_encoding=’utf-8′)
content = tmpl.render(name=request.get[‘name’], data=data)
return response(body=content)
五、url分发控制给不同的资源设计不同的 url, 客户端请求这个 url,web应用程序再根据用户请求的 url 定位到具体功能并执行之。提供一个干净的 url 有很多好处:1. 可读性,通过 url 就可以大概了解其提供什么功能2. 用户容易记住也方便直接输入3.设计良好的 url 一般都更短小精悍,对搜索引擎也 更友好使用selector模块来处理url映射下载地址http://pypi.python.org/pypi/selector, 下载那个source文件进行python setup.py install 首先把urls的配置单独放到urls.py中
# -*- coding: utf-8 -*-
from controller import hello_app
mappings = [(‘/hello/{name}’, {‘get’:hello_app})]
修改main.py
# -*- coding: utf-8 -*-
from wsgiref import simple_server
from urls import mappings
from selector import selector
# 构建 url 分发器
app = selector(mappings)
server = simple_server.make_server(‘localhost’, 8080, app)
server.serve_forever()
然后,在 hello_app 中就可以通过 environ[‘wsgiorg.routing_args’] 获取到 name 参数了,不过在 wsgi_wrapper 其实还可以进一步简化 hello_app 的工作: 直接把解析得到的参数当作函数参数传过去!修改 utils.py:
from webob import request
def wsgi_wrapper(func):
def new_func(environ, start_response):
request = request(environ)
position_args, keyword_args = environ.get(‘wsgiorg.routing_args’, ((), {}))
response = func(request, *position_args, **keyword_args)
return response(environ, start_response)
new_func.__name__ = func.__name__
new_func.__doc__ = func.__doc__
return new_func
那 hello_app 就可以改成这样了:
…
@wsgi_wrapper
def hello_app(request, name=”):
…
content = tmpl.render(name=name, data=data)
return response(body=content)
执行main.py,访问http://localhost:8080/hello/python
总结以上部分的实现,就是类似django框架中的几个主要的功能模块,希望对大家的学习有所帮助。
更多python模拟django框架相关文章请关注php中文网!