Выбрать главу

Рис. 1.13. Экранирование символов HTML

Экранирование текста, как в данном примере, требуется не всегда, но его следует применять, когда содержимое текста заранее не известно, -сценарии, генерирующие разметку HTML, должны следовать правилам ее оформления. Как мы увидим далее в этой книге, похожая функция urllib.parse.quote применяет правила экранирования к тексту в строке с адресом URL. Кроме того, мы увидим, что крупные фреймворки часто решают задачи форматирования текста автоматически.

Веб-интерфейс к хранилищу с данными

Теперь для создания нашего приложения баз данных на основе технологии CGI, представленной в предыдущем разделе, нам потребуется реализовать более крупную форму ввода и отображения данных. На рис. 1.14 изображена форма, которую мы реализуем для доступа к нашей базе данных.

Реализация веб-сайта

Чтобы обеспечить возможность взаимодействий, создадим разметку HTML начальной формы ввода, а также CGI-сценарий на языке Python, который будет отображать полученные результаты и обрабатывать запросы на изменение данных в хранилище. В примере 1.33 приводится разметка HTML формы ввода, которая создает страницу, изображенную на рис. 1.14.

Рис. 1.14. Форма ввода peoplecgi.html

Пример 1.33. PP4E\Preview\peopleegi.html

<html>

<title>People Input Form</title>

<body>

<form method=POST action=”cgi-bin/peoplecgi.py”>

<table>

<tr><th>Key <td><input type=text name=key> <tr><th>Name<td><input type=text name=name> <tr><th>Age <td><input type=text name=age> <tr><th>Job <td><input type=text name=job> <tr><th>Pay <td><input type=text name=pay> </table>

<p>

<input type=submit value=”Fetch”, name=action> <input type=submit value=”Update”, name=action> </form>

</body></html>

Обработкой формы и других запросов будет заниматься CGI-сценарий на языке Python, представленный в примере 1.34, который будет извлекать и изменять записи в нашем хранилище. Обратно он будет возвращать страницу, похожую на ту, что воспроизводит разметка в примере 1.33, но с полями формы, заполненными значениями атрибутов объекта, извлеченного из хранилища.

Как и в реализации графического интерфейса, для вывода результатов и ввода изменений будет использоваться одна и та же веб-страница. В отличие от графического интерфейса, этот сценарий будет запускаться заново в ответ на каждое действие пользователя и каждый раз снова будет открывать базу данных (атрибут action формы содержит ссылку на сценарий для следующего запроса). Модель CGI не предоставляет возможности сохранения информации о состоянии между запросами, поэтому каждый раз мы вынуждены выполнять все действия с самого начала.

Пример 1.34. PP4E\Preview\egi-bin\peopleegi.py

Реализует веб-интерфейс для просмотра и изменения экземпляров классов в хранилище; хранилище находится на сервере (или на том же компьютере, если используется имя localhost)

import cgi, shelve, sys, os    # cgi.test() выведет поля ввода

shelvename = ‘class-shelve’    # файлы хранилища находятся

#    в текущем каталоге

fieldnames = (‘name’, ‘age’, ‘job’, ‘pay’)

form = cgi.FieldStorage()    # парсинг данных формы

print(‘Content-type: text/html’)    # заголовок + пустая строка для ответа

sys.path.insert(0, os.getcwd())    # благодаря этому модуль pickle

#    и сам сценарий будут способны

#    импортировать модуль person

#    главный шаблон разметки html

replyhtml = """

<html>

<title>People Input Form</title>

<body>

<form method=POST action=”peoplecgi.py”>

<table>

<tr><th>key<td><input type=text name=key value=”%(key)s”>

$ROWS$

</table>

<p>

<input type=submit value=”Fetch”, name=action>

<input type=submit value=”Update”, name=action>

</form>

</body></html>

#    вставить разметку html с данными в позицию $ROWS$

rowhtml = ‘ <tr><th>%is<td><input type=text name=%s value=”%%(%s)s”>\n’ rowshtml = ‘’

for fieldname in fieldnames:

rowshtml += (rowhtml % ((fieldname,) * 3)) replyhtml = replyhtml.replace(‘$ROWS$’, rowshtml)

def htmlize(adict):

new = adict.copy()    # значения могут содержать &, >

for field in fieldnames:    # и другие специальные символы,

value = new[field]    # отображаемые особым образом;

new[field] = cgi.escape(repr(value)) # их необходимо экранировать return new

def fetchRecord(db, form): try:

key = form[‘key’].value record = db[key]

fields = record.__dict__    # для заполнения строки ответа