Python 流行 WEB FrameWork 之一《TurboGears快速入门》翻译

 

TurboGears快速入门


在这篇文章当中主要讲解入门教程和关于信息。这篇文章将成为一个很好的入门文档。

这篇文章界于入门文档和手册之间。入门文档覆盖特定知识点,提供快速入门。工作手册提供了具体的工作细节文档。

这份快速入门指南提供了在不需要注意细节情况下的背景知识。

本文档没有包含安装指南,到下载页面会提及相关方法。本指南也没有包含Python的方方面面,可以从很多书籍和资源中得到Python的相关知识。


tg-admin

TurboGears的最终应用是以代码文件的形式存在的。正因为如此,代码是描述编程工具的好方法。生成代码最快的方式是使用tg-admin工具。

tg-adminTurboGears的命令行工具。依靠其子命令可以创建新工程、处理(manipulate)数据库或者以面向对象的特性分析数据库。

tg-admin手册提供了命令细节。如果不提供命令来运行tg-admin,可以得到可用命令列表。

现在,我们使用"quickstart"命令,所以应该使用如下命令:

tg-admin quickstart

如果使用"--help"选项,将会得到命令的帮助信息和选项信息。对快速开始,可以使用命令行或者提示符下设置信息。你不需要经常运行quickstart,因为其实它很简单。

这里使用"gs"作为项目名称和包名称,开始我们的项目:

Enter project name: gs

Enter package name [gs]:

creating directory gs

generating gs/dev.cfg

generating gs/prod.cfg

generating gs/gs-start.py

generating gs/setup.py

creating directory gs/gs

generating gs/gs/__init__.py

generating gs/gs/controllers.py

generating gs/gs/model.py

creating directory gs/gs/sqlobject-history

creating directory gs/gs/static/css

creating directory gs/gs/static/image

creating directory gs/gs/static/javascript

creating directory gs/gs/templates

generating gs/gs/templates/__init__.py

generating gs/gs/templates/master.kid

generating gs/gs/templates/welcome.kid

creating directory gs/gs.egg-info

generating gs/gs.egg-info/sqlobject.txt

running egg_info

writing requirements to ./gs.egg-info/requires.txt

writing ./gs.egg-info/PKG-INFO

writing top-level name to ./gs.egg-info/top_level.txt

这个命令提供给我们一个WEB应用的模板,可以准备填入实际代码。


Starting up the server

当你运行quickstart时,你已经可以随时准备启动CherryPy的内置服务器了。运行开发服务器使用如下步骤:

1、选择新建工程的顶层目录,本例为"cd gs"

2、运行"python 项目名-start.py",本例为"python gs-start.py"

这时将可以看到服务器启动日志。缺省时使用8080端口,所以可以在"http://localhost:8080"得到欢迎页面。如果在MAC系统下,可以在Bonjour书签看到开发站点。

服务器会自动监视文件更改并自动重启。可以在任何时候按下Control+C来停止服务器。


Configuration

快速开始的例子创建了两个配置文件:dev.cfgprod.cfg,启动脚本查找setup.py中的当前目录,如果当前在开发模式则使用dev.cfg配置,否则使用prod.cfg配置文件。可以在启动脚本的命令行中指定使用的配置文件。


The Big Picture

这幅图片包含大量的方框和箭头,但是并没有看起来那么复杂。这幅图展示了简历TurboGears应用所需的所有部分。而且大部分是内含在TurboGears当中的。你的应用程序只需要包含亮紫色的盒子。

  • 你的model(模型)对象描述(represent)应用程序使用的书籍。

  • 你的controller(控制)得到用户浏览器的信息,并使用这些信息更新模型中的信息,并准备好用于显示的视图。当然,控制器也选择需要用于返回数据的视图。

  • TurboGears里,你的view(视图)就是用于显示controller提供的信息的模板(template)

你只需要在应用中提供这三个部分即可,其余部分由TurboGears来代劳。

CherryPy可以方便的产生控制器来从网站上获得用户提交的信息。SQLObject可以方便的定义和使用模型。Kid可以产生优秀的HTML页面供给浏览器的显示。MochiKit可以很好的实现浏览器端的复杂行为(behavior),也可以提过Kid生成AJAX格式的请求。


CherryPy Exposed

CherryPy中,你的网站被描述成一个按照树形组织的对象和他们的方法。按照CherryPy的方式,可以方便的使请求到达目的地。CherryPy指定的请求根路径是cherrypy.root

如果查看gs-start.py脚本,可以看到如下的代码:

from gs.controllers import Root

cherrypy.root=Root()

按照习俗(convertion),根控制器类叫做"Root",并且从"controllers.py"模块导入。在很小的应用当中,只要一个控制器模块即可。在大型应用中,(by gashero)你将会希望将应用分为多个包。你还可以使用功能分割(divisions)。如果你希望的话,也可以分别导入不同的包到同一处。

当你确定了控制器包之后,Root就是你的WEB应用(webapp)的根对象。

看看下面的代码来理解URL查找和遍历工作:

import turbogears

class HardCodedAddition:

def cantgohere(self):

pass

@turbogears.expose()

def twoplustwo(self):

return "four"

@turbogears.expose()

def fortyplustwo(self):

return "forty-two"

class AlwaysSeven:

@turbogears.expose()

def index(def):

return "7"

class Root:

seven=AlwaysSeven()

add=HardCodedAddition()

@turbogears.expose()

def index(self):

return "Welcome"

@turbogears.expose()

def fun(self):

return "... and yet startlingly productive"

@turbogears.expose()

def default(self,*args):

return "The next parts were %s"%str(args)

按照这种设置,我们可以看到TurboGearsURL遍历工作。这些规则用样作用于CherryPy而并非来自TurboGears

URL路径

返回结果

注释

/

Welcome

如果没有指定,则运行index方法

/fun

... and yet startlingly

如果指定了方法,则直接运行此方法

/seven

重定向到/seven/

子对象按照目录来对待,所以最终被重定向。这是一个很好的特性,可以确保你的相对URL工作正常。

/seven/

7

运行子对象的index方法

/add/cantgohere

错误

这个对象没有被暴露(exposed)CherryPy只导航到暴露的方法

/add/twoplustwo

four

运行子对象的方法

/foobar

The next parts were('foobar')

如果没有找到匹配的URL,则执行default方法

/foobar/baz/bork

The next parts were('foobar','baz','bork')

余下部分的URL被分隔发送到default方法的参数。

在构建对象树时,最好还是设置一个default方法,这样可以很好的探测点击的URL


I wanted an argument!

CherryPy的一个很有趣的特性(当然被TurboGears所使用)是从WEB请求得到的参数会自动转换为调用方法的参数。这将会导致处理WEB请求相当的自然。

可以把root设置成如下样式:

class Root:

@turbogears.expose()

def index(self,name="Arthur"):

return "I am %s, King of the britons"%name

你将会诧异于访问"/"时返回了"I am Arthur, King of the britons"。缺省的参数在未指定时起效。实际上现在就可以传入参数了,并且按照你期望的方式运行。一个形如"/?name=Lancelot"的请求将会返回"I am Lancelot, King of the britons"

有如Python,调用"/?foobar=baz"将会抛出错误,(by gashero)因为这样将调用root.index(foobar="baz")。所以可以使用如下方式避免:

class Root:

@turbogears.expose()

def index(self,name="Arthur",**kw):

return "I am %s, King of the britons"%name

Pythonkw可以接受剩余参数的词典。


Testing, 1... 2... 3...

测试驱动的开发是一种好的开发方式。在编码前先写好测试代码,将会让你明确自己所需要的功能,并提供更好的结构。

如果你不提前写测试,使用自动测试将是更改时的救命者。

当你安装了TurboGears时,可以免费得到TestGearsTestGearsPythonunittest单元测试模块的简单插件,可以免去手动书写测试程序的麻烦。

一份单独(separate)的文档可以覆盖测试的每一个细节。如下是示例控制器代码controllers.py

import turbogears

class Root:

@turbogears.expose(html="gs.templates.welcome")

def index(self,value="0"):

value=int(value)

return dict(newvalue=value*2)

TestGears遍历(look for)模块并启动test_。按惯例(by convertion),测试模块使用单独的包叫做"tests",并放在需要测试的包之下,尽管TestGears并不一定需要这样。如下是简单的测试模块:

from turbogears.tests import util

from gs.controllers import Root

import cherrypy

def test withtemplate():

"测试模板输出"

cherrypy.root=Root()

util.createRequest("/?value=27")

assert "The new value is 54." in

cherrypy.response.body[0]

def test directall():

"测试不使用模板时的方法输出"

d=util.call(cherrypy.root.index,"5")

assert d["newvalue"]==10

注意,这些只是函数测试,并非unittest.TestCases的测试用例。你仍然可以使用unittest.TestCases的测试用例。测试函数必须以"test"开头。docstring提供了测试程序的正常运行输出。

模板测试使用了受欢迎的模板形式,形如"The new value is ${value}."。运行tests,如下:

python setup.py testgears

模板测试按照CherryPy的请求处理机制,所以可以测试各种URL和过滤模板处理。


Validating and converting arguments

TurboGears提供了从表单编码到特定Python类型的验证和简单转换方法,如下是示例:

import turbogears

from turbogears import validators

class Root:

@turbogears.expose(html="gs.templates.welcome",

validators=("value":validators.Int()))

def index(self,value=0):

return dict(newvalue=value*2)

def validation error(self,funcname,kw,errors):

#做一些出错时的处理工作

这个传递给turbogaers.expose的字典告知value参数使用Int类型的验证器。这可以确保调用index函数时,value的值是整数类型。

如果验证失败,则validation_error函数被调用,来替换原始目标方法。第一个参数是字符串型,表示验证失败的方法。可以使用一个专用(appropriate)的模板来报警。第二个参数是传递给原方法的参数字典。最后一个参数是抛出的异常列表(list)

验证失败异常对象提供了用户友好的错误信息。这些对象和原始参数允许你重现(repopulate)一个验证失败的表单入口。

validation_error方法应该做什么呢?他可以做与原方法相同的事情,可以返回字典或字符串,也可以抛出cherrypy.HTTPRedirect来重定向到另外一个页面。这是很好理解的。

所有的验证器(validator)都已经被导入到了turbogears.validators模块中了。可以看到验证器在"FormEncode validators module""TurboGears validators module"中是有效的。

可以在FormEncode验证器框架下做很多更加高级的事情。验证器参数可以传递轮廓(schema?)或字典。更多关于轮廓(schema)的信息,参照"FormEncode Validator"文档。


How a view template is chosen

上面已经看过一些使用turbogears.expose中的html参数的引用。这里将会继续讲解。

如果单独使用CherryPy,可以返回一个字符串,并且此字符串被发送到客户端浏览器。但是更多时候,需要返回一个WEB页面。使用TurboGears可以使用Kid模板来返回存在字典中的变量,并传递的html参数到turbogears.expose

html参数给出了获得Kid模板的完整Python包路径。在项目中,位置应该是"项目名.templates"。模板文件以.kid做扩展名,但只要指定html参数,可以不用在乎这些。所以如果模板叫做"Welcome",则应该使用html="项目名.templates.welcome"

返回的字典中应该填入需要传递给模板的任何变量。例如返回dict(newvalue=5),则模板中$(newvalue)被替换为5

有时可能会发现需要一些其他的模板。如果返回的字典包含"tg_template"键,则会自动换用模板系统。返回dict(tg_template="项目名.templates.lancelot")将会使用lancelot模板系统,而不是使用html参数。


Returning XML instead of HTML

最初的Kid是一种基于XML的模板语言。配合HTML串行化器,可以很好的处理HTML。但是使用其他串行化器时,也可以产生XHTML或其他XML格式。

expose(暴露)方法允许指定格式(可以是"json"Kid的其他串行化器)和内容类型(content_type)。例如,如果你想返回RSS,则可以按照如下配置expose方法:

@turbogears.expose(template="project.templates.rss",

format="xml",content_type="text/xml+rss")

expose方法缺省生成HTML代码,但是更改类型也很容易。注意expose方法要求传递模板到"template"参数代替"html"参数。


Brief introduction to Kid templates

Kid模板系统可以是任何的XML文档,但是需要包含Kid可以处理的命名空间(namespace)。下面的例子使用了XHTML文档,转换为有效的HTML文档。

这个例子演示了Kid模板:

<?python title="A Kid Test Document"

fruits=["apple","orange","kiwi","M&M"]

from platform import system?>

<html xmlns:py="http://purl.org/kid/ns#">

<head>

<title py:content="title">This is replaced.</title>

</head>

<body>

<p>These are some of my favorite fruits:</p>

<ul>

<li py:for="fruit in fruits">

I like ${fruit}s

</li>

</ul>

<p py:if="system()=='Linux'">

Good for you!

</p>

</body>

</html>

Kid模板的注意事项:

不要忘记定义py这个XML命名空间,这是用来让模板识别出有效XML的关键。

${}用于简单的变量替换,随处可用。

$foo可以替换为foo,但是并不象使用${}那么安全,因为不方便检测变量结束。

这是XHTML,所以必须关闭所有标签,例如HTML中的<br>,到了XHTML中必须写成<br/>。这是转换成HTML所必须的。

因为模板需要使用有效的XML,所以如果你的JavaScript中包含"<" ">",则需要放在<![CDATA[]]>段中。

Kid模板包含一些特定的保留字,如writeserializerserialize generateinitializepullcontenttransform。应该避开这些保留字。

Kid一个比较好的特性是,可以在其中所有已知的Python特性。Kid模板将会被编译成Python代码来控制模板的行为。例如:py:for="fruit in fruits"行为表示Python中的"for fruit in fruits:"

词典中定义的变量是模板的全部可用变量。所有的"py"属性将使用Python的本地变量。如py:for="fruit in fruits"的例子,"fruits"就是一种经由(via)字典传递的序列(iterable)类型。

当模板中的变量被遗弃时,Kid自动避开。你也不需要在意包含"<"的值。例如,你需要确定是否真的需要使用XHTML时。如果是,则将你包装的替换值放入XML()中。例如,我们需要一个叫做"header"XHTML段。可以表示为${XML(header)},这样"header"将会被丢弃(drop)而自动避开(escape)

推荐阅读Kid属性语言。

http://kid.lesscode.org/language.html#attribute-language


Being Designer-Friendly

如果使用了XHTML,可以使用FireFox浏览器直接打开Kid模板。如果对你很有用,可以这样在浏览器中查看来校准模板外观。

你在找什么?样式表,JavaScript还是变量替换。

有时,使用样式表的href时并非可以达到很好的所见(by gashero)即所得。为了避免(get around)这些,可以使用href来处理浏览器中的模板视图,并且py:attrs来处理生成页面。如:

<link rel="stylesheet" type="text/css"

href="/Path/To/File.css"

py:attrs="href='/path/on/website'"/>

当在浏览器中查看模板时,浏览器只查看href属性,所以样式表可以很好的加载。当模板将要生成最终视图(final viewing)时,Kid将会替换py:attrs中的值,所以样式表可以很好的工作。当处理JavaScript时,这里同样使用src属性来标记脚本。


Application-wide Headers and Footers

pp


Template variables you get for free

pp


Using URLs

pp


JSON outputs

pp


Brief introduction to MochiKit

pp


Defining your model

模型是应用操作的数据。TurboGears模型使用SQLObject对象。SQLObject提供了Python对象到关系数据库的桥梁。它并不是设计用来完全隐藏数据库的,未来的设计目标是可以使用Python代码而不是错误的SQL语句。

TurboGears存取数据库之前,必须指定如何找到数据库。可以在dev.cfgprod.cfg配置文件中设置。参数"sqlobject.dburi"控制了数据库的存储位置,并使用标准的URI风格。

当然也可以在连接URI中提供"query parameters"选项。一对(couple)有用的选项是debugdebugOutput。如果添加了"?debug=1"URI,每个查询都会输出运行状态。如果添加了"&debugOutput=1",则可以看到查询结果。

可以在工程目录的model.py中定义数据模型。如果确实很需要将数据保存在多个模块中,也可以将其分布在多个模块中,并确保被model导入。SQLObject提供两种不同的方式定义数据库:可以直接在数据库中定义SQL语句,或在Python中定义。为了代码的简洁,在Pythonmodel中定义更好些。如果希望一个Python类联系到数据库,可以按照如下:

from sqlobject import *

class Bookt(SQLObject):

class sqlmeta:

fromDatabase=True

注意这只在某些数据库中有效,具体参考SQLObject文档。

Python类中定义模型需要输入Python代码,但可以避免书写SQL语句。如下是一个例子BOOK

class Book(SQLObject):

isbn=StringCol(length=13,alternateID=True)

title=StringCol(length=100)

description=StringCol()

authors=RelatedJoin("Author")

class Authors(SQLObject):

last_name=StringCol(length=40)

first_name=StringCol(length=40)

books=RelatedJoin("Book")

创建数据库使用如下语句:

tg-admin sql create

这将会创建三个数据库表格,一个是书籍表,一个作者表,一个多对多的联系表来联系他们。

但是SQLObject不能定义所有的数据库模型,但可以在大多数情况下很好的工作。比如无法很好的定义表名、列名和连接名,来适应已有的数据库。

模型对象无需确保对数据容器的沉默。这些模型对象是完整的Python对象,可以拥有自己的方法和做一些复杂(complex)的计算。

更多相关信息详见SQLObject文档。


Using your model

SQLObject可以确保非常方便的访问数据库,有如普通的Python对象一样。SQLObject在后台执行SQL语句来实现这些东东。插入一行记录就是实例化一个对象。下例开启了调试信息(?debug=1&debugOutput=1)

>>> Book(isbn="1234567890",title="A Fistful of Yen", description="An evocative look at ...")

1/QueryIns: INSERT INTO book (isbn,description,title) VALUES ('1234567890','An evocative look at ...','A Fistful of Yen')

1/QueryIns-> 1

1/COMMIT : auto

1/QueryOne: SELECT isbn, title, description FROM book WHERE id=1

1/QueryR: SELECT isbn, title, description FROM book WHERE id=1

1/QueryOne-> (u'1234567890',u'A Fistful of Yen','An ...')

1/COMMIT : auto

<Book 1 isbn='1234567890' title='A Fistful of Yen' description="'An ...'">

虽然有很多种办法来保留一个主键来保持记录的区别,SQLObject最好使用缺省设置的integer类型的主键。你可以使用SQLObject对象的id属性访问内置的主键。SQLObject可以确保很容易的通过ID属性获取对象。

>>> Book.get(1)

当对某一个特定的列指定了"alternateID",比如上例的"isbn"SQLObject自动创建类方法来方便搜索:

>>> Book.byIsbn("1234567890")

当然,更多的时候需要ID之外的查询方式。SQLObject提供了"select"类方法允许制定多种Python形式的查询条件。自定义类的"q"属性提供了存取真实属性的方法。例如,存取isbn列可以用Book.q.isbn。如下例:

>>> list(Book.select(AND(LIKE(Book.q.title,"%Fistfull%"), Book.q.isbn="1234567890")))

在如上例子中,使用list作用于Book.selectselect类方法返回一个SelectResults对象。仅在请求数据时SelectResults返回数据,它只是一个结果的占位符。除了可以将结果转换为list之外,还可以使用SelectResults对象的count()方法得到结果记录数量。

数据更新(update)很简单,只要改变属性即可。每次改变属性,SQLObject对象都会执行UPDATESQL语句。有时,可能需要一次更改多个列。实例拥有set方法允许一次赋值,如下例:

>>> book.title="A Fistful of Foobar"

>>> book.set(title="A Fistful of Yen 2:...",isbn="37")

TurboGears可以方便的使用事务,通过"连接HUB"connection hub在需要时自动连接到数据库,并给出方法供开始(begin),提交(commit) ,回滚(rollback)和结束(end)事务。如下例:

>>> book.title #"1"

>>> hub.begin()

>>> book.title="2"

>>> hub.rollback()

>>> hub.end()

>>> book.title #"2"

>>> book.sync()

>>> book.title #"1"

如上的例子中,先设置了title1,之后回滚(rollback),并结束了事务,这样等于丢弃了修改。此时对象中的值还是2,但是数据库中的值为1。此时再次同步(sync),就将数据库中的值赋予到了对象中,则title再次变为1

不像之前的例子,这里没有"COMMIT : auto"。因为使用了事务之后就自动关闭了自动提交,当然还是可以通过增加一个"autoCommit=0"参数到URI之中来开启这个功能。

当对象与数据库不同步时是很不好的。通过调用sync(),可以同步,就是从数据库中重新装入值。

可以通过destroySelf方法删除本记录。


完成...?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值