Сопоставление строк результатов с namedtuple в python sqlite
я немного играю с api python для sqlite3, у меня есть небольшая таблица для языков хранения с полями id, name и creation_date. Я пытаюсь сопоставить необработанные результаты запроса в namedtuple
как рекомендуют документы, таким образом, я могу управлять строками более читаемым способом, поэтому вот мой namedtuple
.
LanguageRecord = namedtuple('LanguageRecord', 'id, name, creation_date')
код, который предлагают документы для сопоставления, выглядит следующим образом:
for language in map(LanguageRecord._make, c.fetchall()):
# do something with languages
это нормально, когда я хочу вернуть коллекцию языках, но в это дело я хочу просто чтобы получить один язык:
c.execute('SELECT * FROM language WHERE name=?', (name,))
Итак, моя первая попытка была примерно такой:
language = map(LanguageRecord._make, c.fetchone())
этот код не работает, потому что fetchone()
возвращает кортеж вместо списка с одним кортежем,
так что
3 ответов
есть гораздо более простой способ! Sqlite3 предоставляет пользователю возможность определить "row factories". Эти фабрики строк берут курсор и строку кортежа и могут возвращать любой тип объекта, который он хочет.
как только вы установите фабрику строки с
con.row_factory = my_row_factory
тогда строки, возвращаемые курсором, будут результатом my_row_factory
применяется к строке кортежа. Например,
import sqlite3
import collections
LanguageRecord = collections.namedtuple('LanguageRecord', 'id name creation_date')
def namedtuple_factory(cursor, row):
return LanguageRecord(*row)
con = sqlite3.connect(":memory:")
con.row_factory = namedtuple_factory
cur = con.cursor()
cur.execute("select 1,2,3")
print(cur.fetchone())
доходность
LanguageRecord(id=1, name=2, creation_date=3)
другой пример как определить namedtuple фабрики, см. этот пост.
кстати, если вы установите
conn.row_factory = sqlite3.Row
затем строки возвращаются в виде диктов, ключи которых являются именами столбцов таблицы. Таким образом, вместо доступа к частям namedtuple с такими вещами, как row.creation_date
вы можете просто использовать встроенный sqlite3.Row
row factory и получить доступ к эквиваленту с row['creation_date']
.
улучшение row_factory
на самом деле это, который может быть использован для всех видов запросов:
from collections import namedtuple
def namedtuple_factory(cursor, row):
"""Returns sqlite rows as named tuples."""
fields = [col[0] for col in cursor.description]
Row = namedtuple("Row", fields)
return Row(*row)
conn = sqlite3.connect(":memory:")
conn.row_factory = namedtuple_factory
cur = con.cursor()
Я думаю, что лучше использовать
for language in map(LanguageRecord._make, c.fetchall()[:1]):
Потому что это может вызвать IndexError с fetchall()[0].
Если вам нужен один результат, и в запросе уже есть "где". Как я понимаю запрос должен возвращать одну строку. Ранняя оптимизация-это зло. :)