当前位置: 首页 > 工具软件 > web.py > 使用案例 >

web.py 教程

宗涵蓄
2023-12-01

http://webpy.org/tutorial3.zh-cn

http://blog.sina.com.cn/s/blog_69812f770100xrk6.html

安装


可以从 github.com/webpy/webpy 里获得最新的 web.py
执行下列命令抓取
git clone    git://github.com/webpy/webpy.git

git clone  git://github.com/webpy/webpy.git

之后可以直接将抓回来的 webpy/web/ 文件夹拷到 web.py 程序目录里使用,
或者执行下列命令将 web.py 安装到系统里
cd webpy
python setup.py build
sudo python setup.py install
此外,也许您还需要安装 python-cheetah, python-flup

第一个程序

第一个程序就以 你好,世界 来开始吧
# -*- coding: UTF-8 -*-
#!/usr/bin/python

import web

# URL 规则
urls = (
    '/(.*)', 'hello'
)

# 应用程序
app = web.application(urls, globals())

class hello:
    def GET(self, name):
        if not name: name = 'world'
        web.header('Content-Type', 'text/html; charset=UTF-8')
        return '你好,' + '世界' + '!'

# 启动
if __name__ == "__main__":
    app.run()

将他保存为 code.py,在命令行执行
python code.py
现在这个 web.py 应用程序就运行了一个 web 服务器默认监听 8080 端口了,在浏览器中访问 http://0.0.0.0:8080/,应该就可以看到 “您好,世界!” 了。

在命令行的 code.py 后加参数 "IP 地址:端口" 来控制 web 服务器的监听范围
比如监听 8000 端口
python code.py 0.0.0.0:8000
或者,只接受 192.168.1.25 来的 8086 端口
python code.py 0.0.0.0:8000

URL 处理

web.py 0.3 有两种方式处理 URL,
有 urls 指定,或由元类自动映射

正则映射

web.application() 用 urls 将路径的正则匹配映射到元类
import web



urls = (

    "/hello", "hello",

    "/magic/.*", "magic"

)



app = web.application(urls, globals())

自动映射

web.auto_application() 类似于 web.application() ,但自动根据元类来构造 urls
import web



app = web.auto_application()



class hello(app.page):

    def GET(self):

        return "hello, world!"

开发



静态文件

重定向


多个应用程序

web.py 支持集成多个应用程序,或说将应用划分到多个子应用程序。

比如将 /blog 分出在 blog.py 里边

blog.py:
import web

urls = (

  "",      "reblog",

  "/(.*)", "blog",

)



class reblog:

    def GET(self): raise web.seeother('/')



class blog:

    def GET(self, path):

        return "blog " + path



app_blog = web.application(urls, locals())
code.py:
import web

import blog

urls = (

  "/blog", blog.app_blog,

  "/(.*)", "index",

)



class index:

    def GET(self, path):

        return "hello " + path



app = web.application(urls, locals())

基于子目录的应用程序

可以根据子目录来划分应用程序,

比如将 wiki.py , blog.py ,auth.py 分出来

import web



import wiki

import blog

import auth



mapping = (

 "/wiki", wiki.app,

 "/blog", blog.app,

 "/auth", auth.app,

)



app = web.subdir_application(mapping)

基于子域名的应用程序

也可以根据子域名来划分应用程序,这可以方便做 virtual hosting

比如

www.example.com (和 example.com)是 mainsite
XXXX.example.com 是 usersite

import web



import mainsite

import usersite



mapping = (

 "(www\.)?example.com", mainsite.app,

 ".*\.example.com", usersite.app,

)



app = web.subdomain_application(mapping)


测试

doctest

import web



urls = (

    "/hello", "hello",

)



app = web.application(urls, globals())



class hello:

 """Hello world example.



     >>> response = app.request("/hello")

     >>> response.data

     'hello, world!'

     >>> response.status

     '200 OK'

     >>> response.headers['Content-Type']

     'text/plain'

 """

 def GET(self):

     web.header('Content-Type', 'text/plain')

     return "hello, world!"


unittest

import unittest

from helloworld import app



class HelloWorldTest(unittest.TestCase):

 def testHelloWorld(self):

     response = app.request('GET', '/')

     self.assertEquals(response.data, 'hello, world!')

     self.assertEquals(response.headers['Content-Type'],  

'text/plain')

     self.assertEquals(response.status, '200 OK')



if __name__ == "__main__":

 unittest.main()


会话

session

web.py 0.3 正式提供了基于 cookie 的 session 支持。

import web



urls = (

    "/count", "count",

    "/reset", "reset"

)



app = web.application(urls, locals())

session = web.session.Session(app, web.session.DiskStore('sessions'), initializer={'count': 0})



class count:

    def GET(self):

        session.count += 1

        return str(session.count)



class reset:

    def GET(self):

        session.kill()

        return ""



if __name__ == "__main__":

    app.run()

上边 Session 的 initializer 参数可以是 dict 或func,用来初始化 session。

web.py 的 session 存储有基于文件的 DiskStore 和基于数据库的 DBStore ,上边例子是DiskStore。

也可以使用基于数据库的 DBStore

使用 DBStore session 前需要在数据库建表
create table sessions (

    session_id char(128) UNIQUE NOT NULL,

    atime datetime NOT NULL default current_timestamp,

    data text

);
然后就可以
db = web.database(dbn='postgres', db='mydatabase', user='myname', pw='')

store = web.session.DBStore(db, 'sessions')

session = web.session.Session(app, store, initializer={'count': 0})

cookies

设置

可以用 web.setcookie() 、web.cookies() 来设置和读取 cookies

参数:
web.setcookie(name, value, expires="", domain=None, secure=False)
  • name (string) - The actual name of the cookie,as stored by the browser, and returned to the server.
  • value (string) - The value you want storedunder that name.
  • expires (int) - Optionally, is the time inseconds until the browser should expire the cookie. Note: this mustbe an integer, not a string.
  • domain (string) - The domain the cookie isvalid for. By default, set to the host accessed, this allows you toset the domain, rather than just a host (such as .webpy.org).
  • secure (bool)- If True, require that thecookie only be sent over HTTP/S.
例子
class CookieSet:

    def GET(self):

        i = web.input(age='25')

        web.setcookie('age', i.age, 3600)

        return "Age set in your cookie"

读取

有两个方法读取 cookie
1. 当 cookie 不存在时抛出异常
web.cookies().get(cookieName)  

    #cookieName is the name of the cookie submitted by the browser
2. 有预设值,避免异常
foo = web.cookies(cookieName=defaultValue)

foo.cookieName   # return the value (which could be default)

    #cookieName is the name of the cookie submitted by the browser
例子:

通过 web.cookies() 来访问

如果先前 web.setcookie() 设置了 age , 那可以这样读取

class CookieGet:

    def GET(self):

        c = web.cookies(age="25")

        return "Your age is: " + c.age
上边的当没有 cookie 时会异常,如果要考虑没有 cookie 的情况,可以类似下边这样:
class CookieGet:

    def GET(self):

        try: 

             return "Your age is: " + web.cookies().get('age')

        except:

             # Do whatever handling you need to, etc. here.

             return "Cookie does not exist."

发邮件

用 gmail 发邮件

先用 web.config 配置 smtp

web.config.smtp_server = 'smtp.gmail.com'

web.config.smtp_port = 587

web.config.smtp_username = 'cookbook@gmail.com'

web.config.smtp_password = 'secret'

web.config.smtp_starttls = True

再用类似下边的发邮件

web.sendmail('cookbook@gmail.com', 'user@example.com', 'subject', 'message')
或者可以附上邮件头
web.sendmail('cookbook@webpy.org', ['user@example.com', 'user2@example.com'],

        'subject', 'message',

        cc='user1@example.com', bcc='user2@example.com',

        headers=({'User-Agent': 'webpy.sendmail', 'X-Mailer': 'webpy.sendmail',})

        )

获取客户端信息

web.ctx


例子

class example:

    def GET(self):

        referer = web.ctx.env.get('HTTP_REFERER', 'http://google.com')

        useragent = web.ctx.env.get('HTTP_USER_AGENT')

        raise web.seeother(referer)

ctx 里的数据

Request

  1. environ a.k.a. env — adictionary containing the standard WSGI environment variables
  2. home — the base path for the applicationhttp://example.org
  3. homedomain — ??? http://example.org
  4. homepath — ???
  5. host — the domain requested by the userexample.org
  6. ip — the IP address of the userxxx.xxx.xxx.xxx
  7. method — the HTTP method used GET
  8. path — the path requested by the user/articles/845
  9. protocol — the protocol used https
  10. query — an empty string if there are no queryarguments otherwise a ? followed by the query string?foo=amorphous&bar=blasphemous
  11. fullpath a.k.a. path + query — the full pathrequested including query arguments/articles/845?foo=amorphous&bar=blasphemous

Response

  1. status — the HTTP status code (default '200OK') 401 Unauthorized
  2. headers — a list of 2-tuples containing HTTPheaders
  3. output — a string containing the responseentity

模板

web.py 支持模板(注意需要 python-cheetah)

先看看将 第一个程序 改为使用模板

写入 templates/hello.html :

$def with (name, todos={})



$if name:

    <h1>你好,$name!</h1>

$else:

    <h1>你好,世界!</h1>

注意模板文件首行要个 $def with()

code.py 里用

render = web.template.render('templates/')

class hello:

    def GET(self, name):

        return render.hello(name)

变量替换

Look, a $string. 

Hark, an ${arbitrary + expression}. 

Gawk, a $dictionary[key].function('argument'). 

Cool, a $(limit)ing.



Stop, \$money isn't evaluated.

We use basically the same semantics as (rejected) PEP215. Variables can go anywhere in a document.

连接多行

If you put a backslash \ 

at the end of a line \ 

(like these) \ 

then there will be no newline.
这会输出一整行

异常

Here are some expressions: 



$for var in iterator: I like $var! 



$if times > max: 

    Stop! In the name of love. 

$else: 

    Keep on, you can do it. 



$try: 

    $get(input) 

$except: 

    Couldn't find it. 



That's all, folks.


注释

$# Here's where we hoodwink the folks at home: 



Please enter in your deets: 



CC: [       ]  $#this is the important one 

SSN: $#Social Security Number#$ [       ]
$# 到行末的是注释

代码

可以将 python 语句放在行首的 "$ " 后(从"$ " 开始,之道行尾,或下一个 "$" )

$def with()

$ mapping = dict(a=[1, 2, 3],

$                b=[4, 5, 6])

<b>$mapping['a'][0]</b>

传递变量

可以这样设置模板里的全局变量
len = 'cn'

web.template.Template.globals[len] = len
或者直接传递 globals()
web.template.Template.globals = globals()

也可以在 metaclass.func 里传递 locals()

class index:

    def GET(self):

        title = '你好,世界'

        entrys = ['第一个', '第二个', '第三个']

        s = web.Storage(locals())

        return render.index(s)
templates/index.html 里用
$def with(s)

...<title>$s.title</title>

...

<ul>

$for entry in s.entrys:

    <li>$entry</li>

</ul>

用户输入

表单

重复表单项

复选框有重复的表单项,譬如http://example.com? id=10& id=20这样的请求,可以用类似下边代码获得多个 id 项值
class SomePage:

    def GET(self):

        user_data = web.input(id=[])

        return "<h1>" + ",".join(user_data.id) + "</h1>"


还可以使用web.data()来获取输入,但这两都有区别

文件上传

例子

import web



urls = ('/upload', 'Upload')



class Upload:

    def GET(self):

        return """<html><head></head><body>

<form method="POST" enctype="multipart/form-data" action="">

<input type="file" name="myfile" />

<br/>

<input type="submit" />

</form>

</body></html>"""



    def POST(self):

        x = web.input(myfile={})

        return "filename: %s\n value: \n%s" % (x['myfile'].filename, x['myfile'].value)



if __name__ == "__main__":

   app = web.application(urls, globals()) 

   app.run()

注意

  1. form 表单必须有属性 enctype="multipart/form-data",否则文件上传会不正常。
  2. 在 webpy 代码里,web.input() 参数必须有默认值(如上边的myfile={} )。否则 web.input 不能获取文件名,而只能获取文件内容。

数据库


web.py 0.3 有更好的 db 处理
import web



db = web.database(dbn='postgres', db='todo', user='you', pw='')



db.select('todo')

db.select('todo', where='id=$id', vars={'id': 2})

db.query('SELECT * FROM todo')

下一步是什么?


 类似资料: