快速入门 — Werkzeug 文档

来自菜鸟教程
Werkzeug/docs/1.0.x/quickstart
跳转至:导航、​搜索

快速入门

文档的这一部分展示了如何使用 Werkzeug 最重要的部分。 它旨在作为对 PEP 333 (WSGI) 和 RFC 2616 (HTTP) 有基本了解的开发人员的起点。

警告

确保从文档建议的位置导入所有对象。 在某些情况下,理论上可以从不同位置导入对象,但这不受支持。

例如,MultiDict 是 werkzeug 模块的成员,但在内部实现了不同的模块。


WSGI 环境

WSGI 环境包含用户请求传输到应用程序的所有信息。 它被传递给 WSGI 应用程序,但您也可以使用 create_environ() 助手创建一个 WSGI 环境字典:

>>> from werkzeug.test import create_environ
>>> environ = create_environ('/foo', 'http://localhost:8080/')

现在我们有一个可以玩的环境:

>>> environ['PATH_INFO']
'/foo'
>>> environ['SCRIPT_NAME']
''
>>> environ['SERVER_NAME']
'localhost'

通常没有人想直接使用环境,因为它仅限于字节串,并且除了手动解析该数据外,不提供任何访问表单数据的方法。


输入请求

为了访问请求数据,Request 对象更有趣。 它包装了 environ 并提供对那里数据的只读访问:

>>> from werkzeug.wrappers import Request
>>> request = Request(environ)

现在您可以访问重要的变量,Werkzeug 将为您解析它们并在有意义的地方解码它们。 请求的默认字符集设置为 utf-8,但您可以通过继承 Request 来更改它。

>>> request.path
u'/foo'
>>> request.script_root
u''
>>> request.host
'localhost:8080'
>>> request.url
'http://localhost:8080/foo'

我们还可以找出用于请求的 HTTP 方法:

>>> request.method
'GET'

通过这种方式,我们还可以访问 URL 参数(查询字符串)和在 POST/PUT 请求中传输的数据。

出于测试目的,我们可以使用 from_values() 方法从提供的数据创建请求对象:

>>> from cStringIO import StringIO
>>> data = "name=this+is+encoded+form+data&another_key=another+one"
>>> request = Request.from_values(query_string='foo=bar&blah=blafasel',
...    content_length=len(data), input_stream=StringIO(data),
...    content_type='application/x-www-form-urlencoded',
...    method='POST')
...
>>> request.method
'POST'

现在我们可以轻松访问 URL 参数:

>>> request.args.keys()
['blah', 'foo']
>>> request.args['blah']
u'blafasel'

提供的表单数据相同:

>>> request.form['name']
u'this is encoded form data'

从这个例子中可以看出,处理上传的文件并不难:

def store_file(request):
    file = request.files.get('my_file')
    if file:
        file.save('/where/to/store/the/file.txt')
    else:
        handle_the_error()

这些文件表示为 FileStorage 对象,这些对象提供了一些常用操作来处理它们。

可以使用 headers 属性访问请求标头:

>>> request.headers['Content-Length']
'54'
>>> request.headers['Content-Type']
'application/x-www-form-urlencoded'

标题的键当然不区分大小写。


标头解析

还有更多。 Werkzeug 提供了对常用 HTTP 标头和其他请求数据的便捷访问。

让我们用典型的 Web 浏览器传输的所有数据创建一个请求对象,以便我们可以使用它:

>>> environ = create_environ()
>>> environ.update(
...     HTTP_USER_AGENT='Mozilla/5.0 (Macintosh; U; Mac OS X 10.5; en-US; ) Firefox/3.1',
...     HTTP_ACCEPT='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
...     HTTP_ACCEPT_LANGUAGE='de-at,en-us;q=0.8,en;q=0.5',
...     HTTP_ACCEPT_ENCODING='gzip,deflate',
...     HTTP_ACCEPT_CHARSET='ISO-8859-1,utf-8;q=0.7,*;q=0.7',
...     HTTP_IF_MODIFIED_SINCE='Fri, 20 Feb 2009 10:10:25 GMT',
...     HTTP_IF_NONE_MATCH='"e51c9-1e5d-46356dc86c640"',
...     HTTP_CACHE_CONTROL='max-age=0'
... )
...
>>> request = Request(environ)

让我们从最无用的头开始:用户代理:

>>> request.user_agent.browser
'firefox'
>>> request.user_agent.platform
'macos'
>>> request.user_agent.version
'3.1'
>>> request.user_agent.language
'en-US'

一个更有用的标头是接受标头。 浏览器通过这个标头通知 Web 应用程序它可以处理哪些 mimetypes 以及处理得如何。 所有接受标题都按质量排序,最好的项目是第一个:

>>> request.accept_mimetypes.best
'text/html'
>>> 'application/xhtml+xml' in request.accept_mimetypes
True
>>> print request.accept_mimetypes["application/json"]
0.8

同样适用于语言:

>>> request.accept_languages.best
'de-at'
>>> request.accept_languages.values()
['de-at', 'en-us', 'en']

当然还有编码和字符集:

>>> 'gzip' in request.accept_encodings
True
>>> request.accept_charsets.best
'ISO-8859-1'
>>> 'utf-8' in request.accept_charsets
True

标准化可用,因此您可以安全地使用替代形式来执行包含检查:

>>> 'UTF8' in request.accept_charsets
True
>>> 'de_AT' in request.accept_languages
True

E-tags 和其他条件标头也以解析形式提供:

>>> request.if_modified_since
datetime.datetime(2009, 2, 20, 10, 10, 25)
>>> request.if_none_match
<ETags '"e51c9-1e5d-46356dc86c640"'>
>>> request.cache_control
<RequestCacheControl 'max-age=0'>
>>> request.cache_control.max_age
0
>>> 'e51c9-1e5d-46356dc86c640' in request.if_none_match
True

回应

响应对象与请求对象相反。 它们用于将数据发送回客户端。 实际上,响应对象只不过是美化的 WSGI 应用程序。

因此,您所做的不是 返回 来自 WSGI 应用程序的响应对象,而是 调用 作为 WSGI 应用程序内的 WSGI 应用程序并返回该调用的返回值。

所以想象一下你的标准 WSGI “Hello World” 应用程序:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return ['Hello World!']

使用响应对象,它看起来像这样:

from werkzeug.wrappers import Response

def application(environ, start_response):
    response = Response('Hello World!')
    return response(environ, start_response)

此外,与请求对象不同,响应对象被设计为可以修改。 因此,您可以使用它们执行以下操作:

>>> from werkzeug.wrappers import Response
>>> response = Response("Hello World!")
>>> response.headers['content-type']
'text/plain; charset=utf-8'
>>> response.data
'Hello World!'
>>> response.headers['content-length'] = len(response.data)

您可以以相同的方式修改响应的状态。 要么只是代码,要么也提供一条消息:

>>> response.status
'200 OK'
>>> response.status = '404 Not Found'
>>> response.status_code
404
>>> response.status_code = 400
>>> response.status
'400 BAD REQUEST'

如您所见,属性在两个方向都起作用。 因此,您可以同时设置 statusstatus_code,更改将反映到另一个。

常见的标头也作为属性或设置/检索它们的方法公开:

>>> response.content_length
12
>>> from datetime import datetime
>>> response.date = datetime(2009, 2, 20, 17, 42, 51)
>>> response.headers['Date']
'Fri, 20 Feb 2009 17:42:51 GMT'

因为 etags 可以是弱的或强的,所以有一些方法可以设置它们:

>>> response.set_etag("12345-abcd")
>>> response.headers['etag']
'"12345-abcd"'
>>> response.get_etag()
('12345-abcd', False)
>>> response.set_etag("12345-abcd", weak=True)
>>> response.get_etag()
('12345-abcd', True)

某些标头可用作可变结构。 例如,大多数 Content- 标头是一组值:

>>> response.content_language.add('en-us')
>>> response.content_language.add('en')
>>> response.headers['Content-Language']
'en-us, en'

同样在这里,这在两个方向上都有效:

>>> response.headers['Content-Language'] = 'de-AT, de'
>>> response.content_language
HeaderSet(['de-AT', 'de'])

身份验证标头也可以这样设置:

>>> response.www_authenticate.set_basic("My protected resource")
>>> response.headers['www-authenticate']
'Basic realm="My protected resource"'

也可以设置 Cookie:

>>> response.set_cookie('name', 'value')
>>> response.headers['Set-Cookie']
'name=value; Path=/'
>>> response.set_cookie('name2', 'value2')

如果标题出现多次,您可以使用 getlist() 方法获取标题的所有值:

>>> response.headers.getlist('Set-Cookie')
['name=value; Path=/', 'name2=value2; Path=/']

最后,如果您设置了所有条件值,则可以针对请求使响应成为条件。 这意味着如果请求可以确保它已经拥有信息,那么除了标头之外不会通过网络发送任何数据,从而节省流量。 为此,您应该至少设置一个 etag(用于比较)和日期标头,然后使用请求对象调用 make_conditional

响应被相应地修改(状态代码更改,响应正文删除,实体标题删除等)