I am playing a bit with the python api for sqlite3, i have a little table for store languages with an id, name and creation_date fields. I am trying to map the raw query res
There is a much easier way! Sqlite3 provides a way for the user to define "row factories". These row factories take the cursor and the tuple row and can return whatever type of object it wants.
Once you set the row factory with
con.row_factory = my_row_factory
then rows returned by the cursor will be the result of my_row_factory
applied to the tuple-row. For example,
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())
yields
LanguageRecord(id=1, name=2, creation_date=3)
For another example of how to define a namedtuple factory, see this post.
By the way, if you set
conn.row_factory = sqlite3.Row
then rows are returned as dicts, whose keys are the table's column names. Thus, instead of accessing parts of the namedtuple with things like row.creation_date
you could just use the builtin sqlite3.Row
row factory and access the equivalent with row['creation_date']
.
I think better to use
for language in map(LanguageRecord._make, c.fetchall()[:1]):
Because it can cause IndexError with fetchall()[0].
If you need one result and there is already "WHERE" in query. As I understand query should return one row. Early optimization is evil. :)
An improved row_factory
is actually this, which can be reused for all sorts of queries:
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()