Рис. 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__ # для заполнения строки ответа