Сопоставление строк результатов с 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].

Если вам нужен один результат, и в запросе уже есть "где". Как я понимаю запрос должен возвращать одну строку. Ранняя оптимизация-это зло. :)