К настоящему моменту в нашем путешествии по SQL и интерфейсу баз данных мы дошли до точки, когда становится неудобно использовать интерактивную оболочку — в начале каждого сеанса и перед началом каждого теста нам приходится снова и снова вводить один и тот же типовой программный код. Кроме того, этот программный код мог бы использоваться в других программах. Давайте преобразуем наш программный код в сценарии, автоматизирующие часто выполняемые задачи и обеспечивающие возможность многократного использования.
Для иллюстрации всей мощи, которой обладает комбинация Python/ SQL, в этом разделе представлены вспомогательные сценарии, выполняющие типичные задачи, которые часто приходится реализовывать во время разработки. Дополнительно большинство этих файлов могут использоваться и как сценарии командной строки, и как модули функций, которые можно импортировать и использовать в других программах. Большинство сценариев в этом разделе также позволяют передавать им имя файла базы данных в аргументе командной строки, что дает возможность использовать в процессе разработки различные базы данных для различных целей — изменение одной из них не будет затрагивать другие.
Сценарии загрузки таблиц
Прежде чем увидеть сценарии в действии, познакомимся с их реализацией — вы можете свободно перепрыгивать вперед и назад, сопоставляя программный код с его поведением. Первым рассмотрим в примере 17.8 способ (не самый лучший) организации в виде сценария логики загрузки таблиц из предыдущего раздела.
Пример 17.8. PP4E\Dbase\Sql\loaddb1.py
загружает таблицу из текстового файла со значениями, разделенными запятыми; его эквивалентом является следующая непереносимая инструкция SQL:
load data local infile ‘data.txt’ into table people fields terminated by
import sqlite3
conn = sqlite3.connect(‘dbase1’)
curs = conn.cursor()
file = open(‘data.txt’)
rows = [line.rstrip().split(‘,’) for line in file]
for rec in rows:
curs.execute(‘insert into people values (?, ?, ?)’, rec)
conn.commit() # подтвердить изменения, если БД поддерживает транзакции conn.close() # close, __del__ вызовут откат, если изменения не подтверждены
В таком виде представленный в примере 17.8 сценарий является сценарием верхнего уровня, предназначенным для использования в строго определенном случае. Однако, приложив совсем немного усилий, его можно разложить на функции, которые можно импортировать и использовать в различных ситуациях. В примере 17.9 представлен намного более полезный модуль и сценарий командной строки.
Пример 17.9. PP4E\Dbase\Sql\loaddb.py
загружает таблицу из текстового файла со значениями, разделенными запятыми обобщенная версия, готовая к многократному использованию
Функции доступны для импортирования;
порядок использования: loaddb.py dbfile? datafile? table?
def login(dbfile): import sqlite3 conn = sqlite3.connect(dbfile) # создать или открыть файл БД curs = conn.cursor() return conn, curs
def loaddb(curs, table, datafile, conn=None, verbose=True):
file = open(datafile) # x,x,x\nx,x,x\n
rows = [line.rstrip().split(‘,’) for line in file] # [[x,x,x], [x,x,x]] rows = [str(tuple(rec)) for rec in rows] # ["(x,x,x)","(x,x,x)"]
for recstr in rows:
curs.execute(‘insert into ‘ + table + ‘ values ‘ + recstr) if conn: conn.commit() if verbose: print(len(rows), ‘rows loaded’)
if __name__ == ‘__main__’: import sys dbfile, datafile, table = ‘dbase1’, ‘data.txt’, ‘people’ if len(sys.argv) > 1: dbfile = sys.argv[1]
if len(sys.argv) > 2: datafile = sys.argv[2]
if len(sys.argv) > 3: table = sys.argv[3]
conn, curs = login(dbfile) loaddb(curs, table, datafile, conn)
Обратите внимание, как здесь используются два генератора списков для конструирования строк со значениями записей для инструкции insert (применяемые преобразования приводятся в комментариях). Мы могли бы также использовать метод executemany, как это делали ранее, но нам требуется обеспечить универсальность и избежать применения жестко определенных шаблонов вставляемых полей — эта функция может использоваться для таблиц с любым количеством столбцов.
В этом файле также определена функция login, автоматизирующая начальное подключение к базе данных, — после ввода последовательности из четырех команд достаточное количество раз эта последовательность выглядит отличным кандидатом на оформление ее в виде функции. Кроме того, при этом снижается избыточность программного кода — в будущем при переходе на другую базу данных логику регистрации придется изменить только в одном месте, при условии, что повсюду используется эта функция login.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011