文档章节

Why so many Python web frameworks?

WeirdBIrd
 WeirdBIrd
发布于 2013/08/10 23:16
字数 2259
阅读 189
收藏 6

为何有如此多的python web frameworks?

当问起python的web framework为什么会这么多时,答案总是:用python来做实在是太容易了。这听起来似乎有一定的道理,因为web framework中的组件很多都实现了,如果能轻松地把它们连接起来,那么就可能降低创建一个新框架的门槛。让我们给出一个实例,我们将使用一些组件,花上一些时间,看看我们能怎样构建一个web framework,我们将把这个框架称之为"Robaccia".

说明:Robaccia是在3个小时内写成的,总共60行python代码。

[更新:在wsgi wiki中添加了连接,清理了一些拼写错误。如果我使用mimetypes模块的话,robaccia.py可能会更小。]

对于我们需要的每种类型的库,我只选一个,也必须只选一个。那是否意味选中的库更好,而其他的就不好呢?答案是否定。它仅仅说明我只能选择一个,不存在优劣问题。如果我没有选择你最爱的templating/routing/sql库,请不要惊奇。

Templating
    在python社区模板库还是挺多的,诸如Myghty,Cheetah等。
    我选择Kid,"它是一个简单的基于xml的模板语言"
SQL
    数据库的接口,我选择sqlalchemy.其他的库有sqlobject.
Routing
    我们对进口的http请求发送到正确的处理器上。为此,
    我选择Selector。其他的选择有Routes.
WSGI
    WSGI,是由PEP 333定义,它是一个概念上胶水层,对于WSGI,
    最好是把它看成像Java servlet api的一样的层。它是位于web
    servers和python web application 或 framework之间的一个标准接口,
    用来增强web application在不同web servers上的移植性。在wsgi
    wiki网站上学习到很多关于wsgi知识,并找到wsgi相关的server,
    framework,middleware等等。

现在我们就使用上面提到的这些组件,开始把它们连接起来。

事实上,你现在可能想走一遍django的指南(如果你还没有读过它的话),它会给你一个大概的内容,也是我们现在想做的事情,可并不是要去完成django指南的所有内容。

我们将使用传统的 model/view/controller 模式,但是在web frameworkd中看起来更像是model/view/template/dispatcher,因此每个application都有4个必须的文件:model.py,view.py,urls.py,和一个templates目录。我们会再放一个文件,dbconfig.py,它是用来允许你建立访问你的数据库。

我们所要做的是通过各个程序片断来建立一个weblog application,要注意这个application的各部件,它是怎样变成framework的一部份的。我们最先需要做的是创建model,在model.py中使用sqlalchemy来建立。

model.py

from sqlalchemy import Table, Column, String
import dbconfig

entry_table = Table('entry', dbconfig.metadata,
             Column('id', String(100), primary_key=True),
             Column('title', String(100)),
             Column('content', String(30000)),
             Column('updated', String(20), index=True)
         )

这是一个纯粹用python描述的model,dbconfig.py中配置同样简单。

dbconfig.py

from sqlalchemy import *

metadata = BoundMetaData('sqlite:///tutorial.db')


在django tutorial中开始做的一件事是使用这样一个model去实际创建数据库中的一个表。我们用manage.py做同样的事,它是Robaccia框架的第一个项目。

manage.py

import os , sys

def create():
    from sqlalchemy import Table
    import model
    for (name, table) in vars(model).iteritems():
        if isinstance(table,Table):
        table.create()

if __name__=="__main__":
    if 'create' in sys.argv:
        create()


现在我们就可以创建数据库了。

$ python manage.py create
$

进入python解释器就能创建数据库表了,通过'model'模块操作数据,注意我们可以进入解释器来创建表,但再继续的话,就要在表中加2行记录了。

$ python
[GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import model
>>> i = model.entry_table.insert()
>>> i.execute(id='first-post', title="Some Title", content="Some pithy text...", 
   updated="2006-09-01T01:00:00Z")

>>> i.execute(id='second-post', title="Moving On", content="Some not so pithy words...", 
   updated="2006-09-01T01:01:00Z")

>>>

现在我们有一个model了,其中还有些数据,是介绍URLs和views的时候了。urls.py文件包含了进口的requests怎样发送到views的信息,view.py包含所有view的目标。

urls.py

import selector
import view

urls = selector.Selector()
urls.add('/blog/', GET=view.list)
urls.add('/blog/{id}/', GET=view.member_get)
urls.add('/blog/;create_form', POST=view.create, GET=view.list)
urls.add('/blog/{id}/;edit_form', GET=view.member_get, POST=view.member_update)


Selector把URIs映射到views上。如果一个进来的请求有一个URI匹配,那这个请求就被分派到相关联的处理器上。Selector和处理器是WSGI对象,它使得把这些内容连接起来变得非常容易。

view.py

import robaccia
import model

def list(environ,start_response):
    rows = model.entry_table.select().execute()
    return robaccia.render(start_response,'list.html',locals())

def member_get(environ,start_response):
    id=environ['selector.vars']['id']
    row=model.entry_table.select(model.entry_table.c.id==id).execute().fetchone()
    return robaccia.render(start_response,'entry.html',locals())

def create(environ,start_response):
    pass

def create_form(environ, start_response):
    pass

def member_edit_form(environ, start_response):
    pass

def member_update(environ, start_response):
    pass

注意上面代码只实现了list()和member_get()。

在我的第一次实现中,view处理器直接作templates激活,然后把所有的东西放在一起以适合WSGI model,但是这样的话对每个view都会重复代码,因此,就有了Robaccia的第二个版本的代码。

robaccia.py

import kid
import os

extensions = {
    'html': 'text/html',
    'atom': 'application/atom+xml'
}

def render(start_response, template_file, vars):
    ext = template_file.rsplit(".")
    contenttype = "text/html"
    if len(ext) > 1 and (ext[1] in extensions):
        contenttype = extensions[ext[1]]

    template = kid.Template(file=os.path.join('templates', template_file), **vars)
    body = template.serialize(encoding='utf-8')

    start_response("200 OK", [('Content-Type', contenttype)])
    return [body]

render()函数会查看template的扩展类型,并使用它来决定content-type的内容。然后模板和变量被传入kid处理。整个过程处理之后,返回的是以WSGI的形式。这里是list.html模板:

list.html

<?xml version="1.0" encoding="utf-8"?>
<html xmlns:py="http://purl.org/kid/ns#>">
  <head>
    <title>A Robaccia Blog</title>
  </head>

  <div py:for="row in rows.fetchall()">
     <h2>${row.title}</h2>
     <div>${row.content}</div>
     <p><a href="./66634226/">${row.updated}</a></p>
  </div>

</html>


现在,urls.urls是一个符合WSGI规范的application,它会监听进来的呼叫,分派到view.py中的WSGI application。其中的每一个都使用model.py的model,然后把结果传到templates目录下的模板,并产生responses.

现在我们需要一个总纲来运行这些代码。既然我们使用的是WSGI application,我们就使用wsgiref。让我们在manage.py中加入一个'run'选项。

manage.py

import os, sys

def create():
    from sqlalchemy import Table
    import model
    for (name, table) in vars(model).iteritems():
        if isinstance(table, Table):
            table.create()

def run():
    import urls
    if os.environ.get("REQUEST_METHOD", ""):
        from wsgiref.handlers import BaseCGIHandler
        BaseCGIHandler(sys.stdin, sys.stdout, sys.stderr, os.environ).run(urls.urls)
    else:
        from wsgiref.simple_server import WSGIServer, WSGIRequestHandler
        httpd = WSGIServer(('', 8080), WSGIRequestHandler)
        httpd.set_app(urls.urls)
        print "Serving HTTP on %s port %s ..." % httpd.socket.getsockname()
        httpd.serve_forever()

if __name__ == "__main__":
   if 'create' in sys.argv:
        create()
   if 'run' in sys.argv:
        run()


run()函数先看环境变量来决定是否做一个CGI application来运行,否则就直接在自己的server 8080端口运行这个application。

$ python manage.py run
Serving HTTP on 0.0.0.0 port 8080 ...

在你的浏览器中指向http://localhost:8080/blog/,你将得到blog的主页,模板会把两个记录填写进前面的list.html中。就是这些了,我们的application运行起来了,我们的framework开始发挥作用了。

如果我们想通过CGI运行我们的application,怎么办呢?那文件只有简单的几行

main.cgi

#!/usr/bin/python2.4

import manage
manage.run()

总结

我们已经作了些什么呢?下面列出的就是在一个目录下的文件集合:
 
    * model.py - 由sqlalchemy Table来创建的一个或多个models
    * view.py - 一个或多个views,作为WSGI application实现
    * urls.py - 一个selector对象单一实例,它把URIs映射到view.py中的
                WSGI application
    * templates - 一个Kid templates的目录,是用作格式化来自view application
                  的响应
    * dbconfig.py - 在model.py中sqlalchemy Tables的配置文件

除了这些文件,还实现的有manage.py,main.cgi,和robaccia.py,这就是我们framework代码的全部内容,总共大约60行代码。就是这些不多的胶水代码把功能强大的库sqlalchemy,Kid,Selector,和WSGIref串在了一起。因为我们整个过程中都是使用WSGI,所以我们能容易通过加载WSGI的代码库,比如处理authentication,caching,logging等。

现在和django比较一下,也清楚地知道我们没有做的东西,我们没有一个admin界面,我们没有一个generic views,自动的form生成器,自动的form处理,django社区,bug跟踪,irc等等。

我想引起大家注意的是那些主要组件的关键点。
我们通过Kid模板来解析model数据写了多少代码?没有。
我们把WSGI views挂接到Selector中写了多少代码?没有。
我们从URLs提取出信息,同时从model提取信息来使用,写了多少代码?只有1行:

id = environ['selector.vars']['id'].

许许多多的组件中可以用来构建python web framework的,有很多好用的。他们只要求很少的一些胶水代码。如果我们选择SQLObject,Cheetah,Routes,我们这个小小framework的代码量也差不多。

哦,要我告诉你为什么要用Robaccia来命名?它的意思是意大利语的"垃圾桶"。它是一个要抛弃的东西。因此,我们要从这开始出发,去看看那些已经构建起来的许许多多的python web framework。

本文转载自:http://ycool.com/post/nr4j9qp

WeirdBIrd

WeirdBIrd

粉丝 164
博文 80
码字总数 87367
作品 0
杭州
私信 提问
部署基于 python wsgi web 框架的工程到函数计算

本文旨在介绍如何将基于 WSGI web 框架构建的工程部署到函数计算 python runtime 的具体操作过程,在介绍操作过程之前,先了解几个概念。 相关概念导读 函数计算 HTTP 触发器 HTTP 触发器是众...

cici是夏莞
2018/05/19
0
0
问个Mac下Python版本和路径的问题

才用Mac不久,问下python版本和路径的问题。 系统自带了几个版本的Python,我个人需要2.6的,版本多了老是冲突。不知道怎么删,我直接把 /System/Library/Frameworks/Python.framework and /L...

四哥
2012/11/16
15.9K
3
mac下安装pygame出错

python下载的版本是:python-2.7.6-macosx10.6(同时本子上还下载安装了python-3.4.0-macosx10.6) pygame下载的版本是:pygame-1.9.1release-python.org-32bit-py2.7-macosx10.3 在windows......

chenye277
2014/03/29
2.9K
2
招聘Python开发工程师 [工作地点:武汉]

Danyang HK is looking for 2 Web application designers and developers for its Wuhan office in order to serve some urgent and fast growing needs for software development from one ......

zfh1979
2011/01/17
1K
17
Mac安装和配置默认Python版本

Mac默认安装了Python2.7 , 查看python版本: python -V 查看python可执行文件路径: which python 安装homebrew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homeb......

还是要坚强
2018/09/21
230
0

没有更多内容

加载失败,请刷新页面

加载更多

nginx学习笔记

中间件位于客户机/ 服务器的操作系统之上,管理计算机资源和网络通讯。 是连接两个独立应用程序或独立系统的软件。 web请求通过中间件可以直接调用操作系统,也可以经过中间件把请求分发到多...

码农实战
今天
5
0
Spring Security 实战干货:玩转自定义登录

1. 前言 前面的关于 Spring Security 相关的文章只是一个预热。为了接下来更好的实战,如果你错过了请从 Spring Security 实战系列 开始。安全访问的第一步就是认证(Authentication),认证...

码农小胖哥
今天
11
0
JAVA 实现雪花算法生成唯一订单号工具类

import lombok.SneakyThrows;import lombok.extern.slf4j.Slf4j;import java.util.Calendar;/** * Default distributed primary key generator. * * <p> * Use snowflake......

huangkejie
昨天
12
0
PhotoShop 色调:RGB/CMYK 颜色模式

一·、 RGB : 三原色:红绿蓝 1.通道:通道中的红绿蓝通道分别对应的是红绿蓝三种原色(RGB)的显示范围 1.差值模式能模拟三种原色叠加之后的效果 2.添加-颜色曲线:调整图像RGB颜色----R色增强...

东方墨天
昨天
11
1
将博客搬至CSDN

将博客搬至CSDN

算法与编程之美
昨天
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部