原文:http://bitworking.org/news/Why_so_many_Python_web_frameworks

BitWorking

This is Joe Gregorio's writings (archives)projects and status updates.

Why so many Python web frameworks?

为什么这么多Python Web框架

When asked about the plethora of web frameworks for Python the answer is often that it is way too easy to put together one in Python. That certainly seems plausible since there are so many libraries that implement the components of a web framework and if it's easy to plug those pieces together then maybe that lowers the bar of entry for new frameworks. So let's give it a shot, we'll pick some components and spend a couple hours seeing how far we can get building a web framework, which we'll call Robaccia.

当被问及为什么有这么多python web框架,一般回答都是:对于Python来说能够非常简单的把很多东西结合成一个整体。似乎看起来的确是这样,因为有很多现成的库已经实现了构造一个web 框架的所需的基本组件,我们能够很容易的把这些零碎的组件组合起来,这样大大降低了创建一个新的web 框架的难度。让我们试一试,我们将会选择一些组件,花费一些时间来展示如何构建一个web框剪,我们称它为 Robaccia。

Executive Summary: Robaccia was built in three hours and a total of 60 lines of Python code.

概要提示:Robaccia是一个只用了三个小时构建的,总共代码只有60行的简单的框架。

[Update: Add a link to the WSGI Wiki and cleaned up some typos. And yes, robaccia.pycould be even shorter if I had used the mimetypes module.]

For each type of library we are going to need I will choose just one. Because I have to. Does that mean that's the library I prefer, or that the other ones are not good? No. It means I had to choose one. Please don't feel slighted if I didn't choose your favorite templating/routing/sql library.

对于每种类型的库,我们将会选择最合适的一个.就因为我这样做,意味着除了我选择的库,其他的库都不好吗?不.它仅仅表示适合我选择.请不要感到沮丧,如果我选择你喜欢的templating/routing/sql库。

Templating(模板)

There are quite a few templating libraries available for Python, such as Myghty,Cheetah, etc. I chose Kid; "a simple template language for XML based vocabularies".

有很多Python模板库,比如 Myghty,Cheetah . 我选择的是  Kid ,一个基于XML词汇表的简单模板语言

SQL

For interfacing to the database I chose SQLAlchemy. There are others likeSQLObject.

Routing

We need some way to route incoming HTTP requests to the right handlers. For this I chose Selector. Again, there are other options in the Python universe like Routes.

WSGI

WSGI, as defined by PEP 333, is the conceptual glue that holds this all together. The best way to think of WSGI is as the Java servlet API for Python. It is a standard interface between web servers and Python web applications or frameworks, to web application portability across a variety of web servers. You can learn more about WSGI and find servers, frameworks, middleware, etc. on the WSGI Wiki

WSGI是由 PEP 333, 定义的,可以理解为把所有东西连在一起的胶水.理解WSGI的最好方式就是WSGI相当于Python中的Servlet.它是web server和web application或者framewokrs之间的标准接口,是为了使得web application能够在任何web servers之间移植.如果你想了解更多细节请参看我之前翻译的 PEP33

Now that we have all of our components let's start plugging them together

所有组件都准备之后,我们开始将它们组合在一起.

Actually, at this point you should probably go off and run through the Django tutorial if you haven't already, to give you an idea of what we are aiming for, not that we are going to get anywhere close to the fit and finish of Django.

事实上,此时如果你还头脑里对这些还没有什么概念,你应该马上去阅读一下Django 手册.

当然只是让你明白我们的目地,而不是让你精通Django.

We're going to follow the classic model/view/controller paradigm, but in the case of web frameworks it is more like model/view/template/dispatcher, so every application will have four required files: model.py, view.py, urls.py and a templates directory. Let's throw in one more file, dbconfig.py that allows you to setup access to your database.

我会依次讲解 model/view/controller 的例子,在web 框架中依次对应 model/template/dispatcher.每个web app都含有四种文件 model.py, view.py, urls.py和templates目录.或者更多的文件,dbconfig.py用于设置访问数据的配置.

What we'll do is start building a weblog application from these pieces but being very careful about what lands in the application and what becomes part of the framework. The first thing we need to create is a model, which we will do using SQLAlchemy, and capture in model.py.

我们将会使用上述提供的组件构建一个weblog运用,对于那些将要成为web framrwork中的部件要非常的小心.我们要做的第一件事就是创建一个model,在这个model中我们将会用到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)

)

Now that's pure a Python description of our model, and the configuration in dbconfig.pyis equally simple.

一个简单的python model描述文件,下面是dbconfig,py的代码非常简单

from sqlalchemy import *
 
metadata = BoundMetaData('sqlite:///tutorial.db')

One of the first things you do in the Django tutorial is use such a model to actually create the tables in the database. We'll do the same here, with 'manage.py' which is the first thing in our Robaccia framework.

在Django手册中要做的第一件事就是使用一个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()

Which we can now use to create the database. 创建数据库

$ python manage.py create
$

Now that our database table is created we can go into the Python interpreter and manipulate the data via the 'model' module. Note that we could have also gone into the interpreter to create the table, but that's not normally how you would proceed. In the interpreter session below we add two rows to the table.

数据表创建完成之后,我们进入Python解释器,引入model.py来操作数据.当然你也直接在解释器中创建表,但是那样不是我们正常的处理方式.我们向表中将插入两条记录.

$ python
Python 2.4.3 (#2, Apr 27 2006, 14:43:58)
[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")
 
>>> 

Now we have a model with some data in it, time to introduce the URLs and the views. The urls.py file contains information on how the incoming requests are to be routed to views, and view.py contains all those view targets.

现在介绍URLs和views.  urls.py 描述了请求将会被路由到那views,views.py包含了所有的视图标记.

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 maps URIs to views. If an incoming request has a URI that matches then the request gets dispatched to the associated handler. Both Selector and the handler are WSGI compliant objects, which will make plugging all this together much easier.

Selector存储了了URIs和Views的映射关系.如果某个请求的URI有匹配的,那么请求将会分发到相应的处理程序. Selector和 handler都是兼容WSGI的对象,使得我们组合起来更加容易

下面是view.py的源码

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

Note that in the above code only list() and member_get() are implemented.

上面的代码我们只实现了 list()和member_get()两个方法

In my first implementation the view handlers originally did the rendering of the templates themselves and then put everything together to fit into the WSGI model, but that was just repeated code for every view, so that code got factored out into our second piece of Robaccia:

在我最初实现的视图处理程序中,我让视图自己渲染模板并且把这些都放在一起以便适应WSGI模型,但是每个试图中都有重复的代码,因此我把这些代码分离到robaccia.py文件中.

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]
 

The render() function looks at the extension of the template and uses that to determine what to use as the content-type. Then the template and variables are passed into Kid to be processed. The whole thing is processed and returned in a way that conforms to WSGI. Here is the list.html template:

render()函数是模板的扩展函数用来确定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="./${row.id}/">${row.updated}</a></p>
</div>
</html>
 

So let's take stock of where we are, urls.urls is a WSGI compliant application that looks at the incoming calls and dispatches to the WSGI compliant applications listed inview.py. Each of those is turn use the model in model.py and pass the results through templates in the templates directory to generate the responses.

Now all we need to do is run the code. Since we are dealing with WSGI applications we can use wsgiref. Let's add a 'run' option to manage.py.

现在我们总结一下我们所作的是.urls是一个WSGI组件 application,它将所有的请求转发到view.py中相应的符合WSGI规范的处理函数.处理函数中使用了model.py进行处理,将model处理的结果传递给templates目录中的模板生成响应结果.

我们现在要做的就是运行代码.我们可以使用wsgiref来处理WSGI application.我们添加一个运行文件 manage.py

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()

The run() function looks at the environment variables to determine if it is being run as a CGI application, otherwise it runs the application under it's own server at port 8080.

run()函数根据环境变量来决定是否以CGI方式运行程序,否则的话自己以server方式运行在8080端口

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

Point your browser at http://localhost:8080/blog/ and you should get the blog's main page, the list.html template filled in with the two entries we put in the system earlier. That's it, our application is running and our framework is functional.

打开浏览器输入http://localhost:8080/blog/ 你将会进入到主页面,list.html显示我们早先插入的两条记录.就这么简单,我们的程序正在运行并且我们的框架发挥作用了.

And what if we want to run our application via CGI? That file is just a few lines long:

如果想以CGI方式运行,只用写以下代码就可以了

main.cgi

#!/usr/bin/python2.4
import manage
manage.run()

Summary(总结)

So what do we have here? A set of conventions for how to lay out files in a directory:

各个文件的作用

  • model.py - One or more models expressed in SQLAlchemy Tables.
  • view.py - One or more views, implemented as WSGI applications.
  • urls.py - A single instance of a selector object that maps URIs to the WSGI applications in view.py.
  • templates - A directory of Kid templates to be used to format the responses from the view applications.
  • dbconfig.py - Configuration for the SQLAlchemy Tables in model.py

Beyond those files which actually implement our example web service we havemanage.pymain.cgi, and robaccia.py, the sum total of our framework code, which comes to about 60 lines of code. That's not a lot of glue code to bring four powerful libraries like SQLAlchemy, Kid, Selector, and WSGIref together. And because we used WSGI throughout we can easily plug in WSGI pieces that handle authentication, caching, logging, etc.

Now let's be clear also about what we do not have when compared to Django. We don't have an instant admin interface, we don't have generic views, automatic form generation, automatic form handling, the Django community, bug tracking, IRC, etc, etc.

What I want to draw your attention to is the touch-points between the major components. How much code did we have to write to make the data model consumable by Kid templates? None. How much translation code did we have to write to hook our WSGI views into Selector? None. And how much code did we have to write to pull information out of URLs and use them in pulling information out of our model? About one line:

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

The nice part about the ocean of components that exists for building Python web frameworks is that the same is true for all of them: they would only require a small amount of glue code. Our little framework would be about the same size if I had instead chosen SQLObject, Cheetah and Routes.

Oh yeah, did I tell you why I chose the name Robaccia? It means trash in Italian. It's a throw away. So go on, get out of here, go work on one of the dozens of already established web frameworks for Python.

为什么这么多Python框架的更多相关文章

  1. python框架之django

    python框架之django 本节内容 web框架 mvc和mtv模式 django流程和命令 django URL django views django temple django models ...

  2. Python框架、库以及软件资源汇总

    转自:http://developer.51cto.com/art/201507/483510.htm 很多来自世界各地的程序员不求回报的写代码为别人造轮子.贡献代码.开发框架.开放源代码使得分散在世 ...

  3. android模拟器(genymotion)+appium+python 框架执行基本原理(目前公司自己写的)

    android模拟器(genymotion)+appium+python 框架执行的基本过程: 1.Push.initDate(openid)方法     //业务数据初始化 1.1   v5db.p ...

  4. 10个用于Web开发的最好 Python 框架

    Python 是一门动态.面向对象语言.其最初就是作为一门面向对象语言设计的,并且在后期又加入了一些更高级的特性.除了语言本身的设计目的之外,Python标准 库也是值得大家称赞的,Python甚至还 ...

  5. 第六篇:web之python框架之django

    python框架之django   python框架之django 本节内容 web框架 mvc和mtv模式 django流程和命令 django URL django views django te ...

  6. Python框架之Django学习

    当前标签: Django   Python框架之Django学习笔记(十四) 尛鱼 2014-10-12 13:55 阅读:173 评论:0     Python框架之Django学习笔记(十三) 尛 ...

  7. Hadoop的Python框架指南

    http://www.oschina.NET/translate/a-guide-to-Python-frameworks-for-Hadoop 最近,我加入了Cloudera,在这之前,我在计算生物 ...

  8. 【python】Python框架、库和软件资源大全

    很多来自世界各地的程序员不求回报的写代码为别人造轮子.贡献代码.开发框架.开放源代码使得分散在世界各地的程序员们都能够贡献他们的代码与创新. Python就是这样一门受到全世界各地开源社区支持的语言. ...

  9. Python框架之Django的相册组件

    Python框架之Django的相册组件 恩,没错,又是Django,虽然学习笔记已经结贴,但是学习笔记里都是基础的,Django的东西不管怎么说还是很多的,要学习的东西自然不会仅仅用十几篇博文就能学 ...

  10. 10款Web开发最佳的Python框架

    Python是跻身于当代IT世界最流行和代码最高效的编程语言之一.Python框架能帮助你快速启动Web应用. 1.CubicWeb CubicWeb的最重要的功能是其代码的可重用性,由一个个代码单元 ...

随机推荐

  1. 解决Qt5使用SSL的“qt.network.ssl: QSslSocket: cannot resolve SSLv2_client_method”错误

    在使用Qt的网络组件连接某些服务器时, 会提示"qt.network.ssl: QSslSocket: cannot resolve SSLv2_client_method"的错误 ...

  2. PPT内嵌视频(指发布时只需要ppt一个文件即可)

    做实验时用手机拍了视频,想把视频嵌入到PPT中.只是单纯的嵌入很容易,但是我想将PPT推送给其他人时,不需要再传视频文件.搜了一下做法,可以通过flash视频格式实现.电脑为thinkpad笔记本,w ...

  3. WCF探索之旅(一)——入门

    背景 对于.NET程序员来说,假设你不知道WCF,那仅仅能说明一点:你还是个菜鸟. 曾经也用.NET做过几个系统,尤其做后面的系统的时候,心里就有点沾沾自喜了! 想着,.NET也就这点东西,我如今也能 ...

  4. linux ptrace II

    第一篇 linux ptrace I 在之前的文章中我们用ptrace函数实现了查看系统调用参数的功能.在这篇文章中,我们会用ptrace函数实现设置断点,跟代码注入功能. 参考资料 Playing ...

  5. Java动态调用webService,axis2动态调用webService

    Java动态调用webService axis2动态调用webService >>>>>>>>>>>>>>>& ...

  6. wordpress密码生成与登录密码验证

    一.研究wordpress时wordpess的密码密码生成与登录密码验证方式很重要 WordPress密码已成为整合的首要目标,如何征服整合,就得了解WordPress密码算法. WordPress系 ...

  7. 如何通过PS制作图片文字效果

    如图这是最终效果,下面我为大家介绍如何制作这种图片文字效果 准备一张图: 方法,步骤: 首先我们打开PHOTOSHOP,插入一张图片. 之后按键盘上面的"T"键快捷键启用文字工具, ...

  8. 使用html5兼容低版本浏览器

    因为html5 新出的一些语义化的标签,在低版本浏览器下不能识别,举个例子,比如你写了一个 header 标签中,写了一段文本,在低版本浏览器下,肯定是能看到的,但是,那是他是不认识 header标签 ...

  9. C# DateTime显示时间格式的使用

    代码DateTime.ToString() Patterns All the patterns: 0 MM/dd/yyyy 08/22/2006 1 dddd, dd MMMM yyyy Tuesda ...

  10. SQL学习:主键,外键,主键表,外键表,数据库的表与表之间的关系;

    在数据库的学习中,对于一个表的主键和外键的认识是非常重要的. 主键:在一个表中,能唯一的表示一个事物(或者一条记录)的字段,我们称之为主键 注意: 主键的设置可以不只是用一个字段,也可以用若干个字段的 ...