Spec-Zone.ru › Werkzeug 0.16

Быстрый старт

В этой части документации показано, как использовать наиболее важные части Werkzeug. Она предназначена в качестве отправной точки для разработчиков с базовым пониманием PEP 333 (WSGI) и RFC 2616 (HTTP).

Предупреждение

Убедитесь, что вы импортируете все объекты из тех мест, которые предлагает документация. Теоретически в некоторых ситуациях можно импортировать объекты из разных мест, но это не поддерживается.

Например, MultiDict является членом модуля werkzeug, но внутренне реализован в другом.

Среда WSGI

Среда WSGI содержит всю информацию, которую запрос пользователя передает приложению. Она передается WSGI-приложению, но вы также можете создать словарь WSGI environ с помощью create_environ() помощника:

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

Теперь у нас есть среда для экспериментов:

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

Обычно никто не хочет работать напрямую со средой environ, потому что она ограничена байтовыми строками и не предоставляет способа доступа к данным формы, кроме ручного парсинга этих данных.

Вход в запрос

Для доступа к данным запроса объект 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 и другим данным запроса.

Давайте создадим объект запроса со всеми данными, которые обычно передает веб-браузер, чтобы мы могли поиграть с ним:

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

Начнем с самого бесполезного заголовка: user agent:

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

Более полезный заголовок — accept header. С помощью этого заголовка браузер сообщает веб-приложению, какие MIME-типы он может обрабатывать и насколько хорошо. Все accept header отсортированы по качеству, лучшим элементом является первый:

>>> 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-tag и другие условные заголовки также доступны в обработанном виде:

>>> 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'

Как видите, атрибуты работают в обоих направлениях. Таким образом, вы можете установить как status, так и status_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'

Поскольку теги etag могут быть слабыми или сильными, существуют методы для их установки:

>>> 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 с объектом запроса.

Ответ изменяется соответствующим образом (изменен код состояния, удален тело ответа, удалены заголовки сущности).

© 2007–2020 Pallets
Licensed under the BSD 3-clause License.
https://werkzeug.palletsprojects.com/en/0.16.x/quickstart/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API