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

fields[‘key’] = key    # использовать словарь атрибутоЕ

except:

fields = dict.fromkeys(fieldnames, ‘?’) fields[‘key’] = ‘Missing or invalid key!’ return fields

def updateRecord(db, form): if not ‘key’ in form:

fields = dict.fromkeys(fieldnames, ‘?’) fields[‘key’] = ‘Missing key input!’ else:

key = form[‘key’].value if key in db:

record = db[key]    # изменить существующую запись

else:

from person import Person    # создать/сохранить новую

record = Person(name=’?’, age=’?’) # evaclass="underline" строки должны быть

# заключены в кавычки

for field in fieldnames:

setattr(record, field, eval(form[field].value)) db[key] = record

fields = record.__dict__

fields[‘key’] = key return fields

db = shelve.open(shelvename)

action = form[‘action’].value if ‘action’ in form else None if action == ‘Fetch’:

fields = fetchRecord(db, form) elif action == ‘Update’:

fields = updateRecord(db, form) else:

fields = dict.fromkeys(fieldnames, ‘?’)    # недопустимое значение

fields[‘key’] = ‘Missing or invalid action!’ # кнопки отправки формы

db.close()

print(replyhtml % htmlize(fields))    # заполнить форму ответа

# из словаря

Сценарий получился таким большим, потому что в его задачу входит обработка ввода пользователя, выполнение операций с базой данных и генерирование разметки HTML для ответа. Тем не менее действует он достаточно прямолинейно и по своему поведению напоминает реализацию графического интерфейса из предыдущего раздела.

Каталоги, форматирование строк и безопасность

Прежде чем двинуться дальше, необходимо сделать несколько важных замечаний. Прежде всего, сценарий веб-сервера, представленный в примере 1.32, должен быть запущен до того, как вы начнете экспериментировать, - он будет перехватывать запросы от броузера и передавать их нашему CGI-сценарию.

Обратите также внимание, что при запуске CGI-сценарий добавляет путь к текущему рабочему каталогу (os.getcwd) в путь поиска модулей sys.path. Не изменяя переменную окружения PYTHONPATH, этот прием позволит модулю pickle и самому сценарию импортировать модуль person, находящийся в том же каталоге, что и сценарий. Из-за нового способа запуска CGI-сценариев, реализованного в Python 3, текущий рабочий каталог не добавляется в список sys.path автоматически, хотя при этом файлы хранилища, находящиеся там, будут обнаруживаться и открываться корректно. Эта особенность в поведении может отличаться, в зависимости от выбранного веб-сервера.

Еще один интересный прием в CGI-сценарии - использование словаря атрибутов записи (__dict__) как источника значений в операции экра

нирования полей внутри выражения форматирования строки, преобразующего строку шаблона HTML в ответ, в последней строке сценария. Напомню, что выражение вида %(key)code заменит ключ key значением этого ключа в словаре:

>>> D = {'say': 5, ‘get’: 'shrubbery'}

>>> D['say']

5

>>> S = '%(say)s => %(get)s' % D

>>> S

‘5 => shrubbery’

Благодаря использованию словаря атрибутов мы можем ссылаться на атрибуты по их именам в форме строк. Фактически часть шаблона ответа генерируется программным кодом. Если его структура кажется вам непонятной, просто вставьте инструкции вывода replyhtml и вызова sys. exit и запустите сценарий из командной строки. Ниже показано, как выглядит разметка HTML таблицы в середине сгенерированного ответа (немного отформатированная здесь для удобочитаемости):

<table>

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

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

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

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

</table>

Далее этот текст заполняется значениями ключей из словаря атрибутов записи инструкцией форматирования строки в конце сценария. Эта инструкция выполняется после того, как словарь будет обработан вспомогательной функцией, преобразующей значения в текст с помощью функции repr и экранирующей текст вызовом функции cgi.escape, в соответствии с требованиями языка разметки HTML (опять же, последний шаг не всегда является обязательным, но он никогда не будет лишним).

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

Справедливости ради следует заметить, что более новый метод str.for-mat позволяет добиться того же эффекта, что и традиционный оператор % форматирования, используемый в сценарии, и дает возможность использовать синтаксис ссылок на атрибуты объектов, который выглядит более явным по сравнению с приемом использования ключей словаря __dict__:

>>> D = {'say': 5, 'get': 'shrubbery’}