На этом шаге мы рассмотрим некоторые атрибуты, позволяющие изменить отображение результатов запроса.
Все рассмотренные методы возвращают запись в виде кортежа. Если необходимо изменить такое поведение и, например, получить записи в виде словаря, то следует воспользоваться атрибутом row_factorу объекта соединения. В качестве значения атрибут принимает ссылку на функцию обратного вызова, имеющую следующий формат:
def <Название функции>(<Объект-курсор>, <Запись>): # Обработка записи return <Новый объект>
Для примера выведем записи из таблицы user в виде словаря:
# -*- coding: utf-8 -*- import sqlite3 def my_factory (c, r): d = {} for i, name in enumerate (c.description): d[name[0]] = r[i] # Ключи в виде названий полей d[i] = r[i] # Ключи в виде индексов полей return d con = sqlite3.connect("catalog.db") con.row_factory = my_factory cur = con.cursor() # Создаем объект-курсор cur.execute("SELECT * FROM user") arr = cur.fetchall() print(arr) # Результат print(arr[0][1]) # Доступ по индексу print(arr[0]["email"]) # Доступ по названию поля cur.close () # Закрываем объект-курсор con.close () # Закрываем соединение input ()
Результат работы приложения:
[{0: 1, 1: 'unicross@mail.ru', 2: 'password1', 'passw': 'password1', 'email': 'unicross@mail.ru', 'id_user': 1}] unicross@mail.ru unicross@mail.ruФункция my_factory() будет вызываться для каждой записи. Обратите внимание на то, что название функции в операции присваивания атрибуту row_factory указывается без круглых скобок. Если скобки указать, то смысл операции будет совсем иным.
Атрибуту row_factory можно присвоить ссылку на объект Row из модуля sqlite3. Этот объект позволяет получить доступ к значению поля как по индексу, так и по названию поля, причем название не зависит от регистра символов. Объект Row поддерживает итерации, доступ по индексу и метод keys(), который возвращает список с названиями полей. Переделаем наш предыдущий пример и используем объект Row:
Архив с файлом можно взять здесь.# -*- coding: utf-8 -*- import sqlite3 con = sqlite3.connect("catalog.db") con.row_factory = sqlite3.Row cur = con.cursor() # Создаем объект-курсор cur.execute("SELECT * FROM user") arr = cur.fetchall() print(type(arr[0])) # <class 'sqlite3.Row'> print(len(arr[0])) # 3 print(arr[0][1]) # Доступ по индексу print(arr[0]["email"]) # Доступ по названию поля print(arr[0]["EMAIL"]) # He зависит от регистра символов for elem in arr[0]: print(elem) print(arr[0].keys()) # ['id_user', 'email', 'passw'] cur.close () # Закрываем объект-курсор con.close () # Закрываем соединение input ()Результат работы приложения:
<class 'sqlite3.Row'> 3 unicross@mail.ru unicross@mail.ru unicross@mail.ru 1 unicross@mail.ru password1 ['id_user', 'email', 'passw']Как видно из результатов предыдущих примеров, все данные, имеющие в SQLite тип TEXT, возвращаются в виде строк. В предыдущих шагах мы создали базу данных testdb.db и сохранили данные в полях таблицы в кодировке Windows-1251. Попробуем отобразить записи из таблицы с рубриками:
>>> con = sqlite3.connect ("testdb.db") >>> cur = con.cursor() >>> cur.execute ("SELECT * FROM rubr") <sqlite3.Cursor object at 0x026A1560> >>> cur.fetchone() (1, '?ЁюуЁрььшЁютрэшх') >>> con.close()При осуществлении преобразования предполагается, что строка хранится в кодировке UTF-8. Так как в нашем примере мы используем другую кодировку, то получается такой результат. Изменить его позволяет атрибут text_factory объекта соединения. В качестве значения атрибута указывается ссылка на функцию, которая будет использоваться для осуществления преобразования значения текстовых полей. Например, чтобы вернуть последовательность байтов, следует указать ссылку на функцию bytes ():
>>> con = sqlite3.connect ("testdb.db") >>> con.text_factory = bytes # Название функции без круглых скобок! >>> cur = con.cursor () >>> cur.execute ("SELECT * FROM rubr") <sqlite3.Cursor object at 0x023C6DA0> >>> cur.fetchone() (1, b'\xe2\x95\xa7\xd0\x81\xd1\x8e\xd1\x83\xd0\x81\xd1\x80\xd1 \x8c\xd1\x8c\xd1\x88\xd0\x81\xd1\x8e\xd1\x82\xd1\x80\xd1\x8d\xd1\x88\xd1\x85')Если необходимо вернуть строку, то внутри функции обратного вызова следует вызвать функцию str() и явно указать кодировку данных. Функция обратного вызова должна принимать один параметр и возвращать преобразованную строку. Выведем текстовые данные в виде строки:
>>> con.text_factory = lambda s: str (s, "cp1251") >>> cur.execute ("SELECT * FROM rubr") <sqlite3.Cursor object at 0x023C6DA0> >>> cur.fetchone () (1, 'Программирование') >>> con.close ()На следующем шаге мы рассмотрим управление транзакциями.