29

I'm using sqlite3 in python 2.5. I've created a table that looks like this:

   create table votes (
      bill text,
      senator_id text,
      vote text)

I'm accessing it with something like this:

v_cur.execute("select * from votes")
row = v_cur.fetchone()
bill = row[0]
senator_id = row[1]
vote = row[2]

What I'd like to be able to do is have fetchone (or some other method) return a dictionary, rather than a list, so that I can refer to the field by name rather than position. For example:

bill = row['bill'] 
senator_id = row['senator_id']
vote = row['vote']

I know you can do this with MySQL, but does anyone know how to do it with SQLite?

Thanks!!!

dreftymac
  • 31,404
  • 26
  • 119
  • 182
  • 3
    possible duplicate of [How can I get dict from sqlite query?](http://stackoverflow.com/questions/3300464/how-can-i-get-dict-from-sqlite-query) – vy32 Aug 22 '15 at 22:49
  • Possible duplicate of [How to retrieve SQL result column value using column name in Python?](https://stackoverflow.com/questions/10195139/how-to-retrieve-sql-result-column-value-using-column-name-in-python) – Eggcellentos Jul 18 '19 at 12:52

8 Answers8

76

There is actually an option for this in sqlite3. Change the row_factory member of the connection object to sqlite3.Row:

conn = sqlite3.connect('db', row_factory=sqlite3.Row)

or

conn.row_factory = sqlite3.Row

This will allow you to access row elements by name--dictionary-style--or by index. This is much more efficient than creating your own work-around.

Eric
  • 2,300
  • 3
  • 22
  • 29
  • 3
    This is actually advised explicitly in `sqlite3` module docs: http://docs.python.org/library/sqlite3.html#row-objects " – heltonbiker Oct 27 '11 at 15:35
  • 4
    Be careful however when using sqlite3.Row, you can't use the row[1:3] syntax anymore, nor can you use a row generator as input for an INSERT statement. The sqlite3.Row is actually a butchered implementation. – xApple Dec 08 '11 at 14:06
  • According to docs it should be conn = sqlite3.connect('db', factory=sqlite3.Row)? – andig Jan 08 '13 at 08:28
  • 1
    @andig: Could you give a link to the doc to which you're referring? The ones I've looked at indicate that member of the `conn` object we're assigning is `row_factory`. It could have changed, I suppose; it's been almost three years since I gave this answer. – Eric Jan 08 '13 at 17:54
  • @Eric: Newbie's mistake- referring to http://docs.python.org/2/library/sqlite3.html I was looking at the connection's, not the row's factory :( – andig Jan 08 '13 at 21:59
  • Note that this does not return an actual dictionary, as the question requested. – zr0gravity7 Feb 17 '23 at 21:59
20

The way I've done this in the past:

def dict_factory(cursor, row):
    d = {}
    for idx,col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

Then you set it up in your connection:

from pysqlite2 import dbapi2 as sqlite
conn = sqlite.connect(...)
conn.row_factory = dict_factory

This works under pysqlite-2.4.1 and python 2.5.4.

Colin Burnett
  • 11,150
  • 6
  • 31
  • 40
  • 6
    Not even quick and dirty, the row_factory hook would be the sanest way to do this per-connection. Mind you, at least the builtin sqlite3 module already comes with a suitable row factory: sqlite3.Row [ http://docs.python.org/library/sqlite3.html#row-objects ] – millimoose May 01 '09 at 16:37
  • Thank you! The method dict_factory() works on psycopg2 (postgres), too. – guettli Dec 13 '11 at 14:30
11

I was recently trying to do something similar while using sqlite3.Row(). While sqlite3.Row() is great for providing a dictionary-like interface or a tuple like interface, it didn't work when I piped in the row using **kwargs. So, needed a quick way of converting it to a dictionary. I realised that the Row() object can be converted to a dictionary simply by using itertools.

Python 2:

db.row_factory = sqlite3.Row
dbCursor = db.cursor()
dbCursor.execute("SELECT * FROM table")
row = dbCursor.fetchone()

rowDict = dict(itertools.izip(row.keys(), row))

Or in Python 3, more simply:

dbCursor = db.cursor()
dbCursor.execute("SELECT * FROM table")
row = dbCursor.fetchone()
rowDict = dict(zip([c[0] for c in dbCursor.description], row))

Similarly, you can use the dbCursor.fetchall() command and convert the entire set of rows to a list of dictionaries in a for loop.

matt2000
  • 1,064
  • 11
  • 17
lexxonnet
  • 136
  • 1
  • 2
5

Sure, make yourself a DictConnection and DictCursor as explained and shown at http://trac.edgewall.org/pysqlite.org-mirror/wiki/PysqliteFactories for example.

ryanday
  • 2,506
  • 18
  • 25
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
2

I know you're not asking this, but why not just use sqlalchemy to build an orm for the database? then you can do things like,


entry = model.Session.query(model.Votes).first()
print entry.bill, entry.senator_id, entry.vote

as an added bonus your code will be easily portable to an alternative database, and connections and whatnot will be managed for free.

si28719e
  • 2,135
  • 5
  • 20
  • 22
1

I've used this:

def get_dict(sql):
    return dict(c.execute(sql,()).fetchall())

Then you can do this:

c = conn.cursor()
d = get_dict("select user,city from vals where user like 'a%'");

Now d is a dictionary where the keys are user and the values are city. This also works for group by

vy32
  • 28,461
  • 37
  • 122
  • 246
1

Simple solution, initialize a cursor object:

cursor = conn.cursor(buffered = True, dictionary = True)

Another option:

cursor = conn.cursor(MySQLdb.cursors.DictCursor)

Rest of Code:

query = "SELECT * FROM table"
cursor.execute(query)
row = cursor.fetchone()

Sources: mysql.connector.cursor , MySQLdb.cursors.DictCursor

Eggcellentos
  • 1,570
  • 1
  • 18
  • 25
0

I use something like this:

class SqliteRow(object):
    def __init__(self):
        self.fields = []

    def add_field(self, name, value):
        self.fields.append(name)
        setattr(self, name, value)

    def to_tuple(self):
        return tuple([getattr(self, x) for x in self.fields])

with this:

def myobject_factory(cursor, row):
    myobject= MyObject()
    for idx, col in enumerate(cursor.description):
        name, value = (col[0], row[idx])

        myobject.add_field(name, value)
    return myobject

MyObject() is a class that inherits from SqliteRow. SqliteRow class is a base class for every object that I want to have returned by a query. Every column becomes an attribute and is logged into the fields list. Function to_tuple is used to change the whole object to a form suitable for queries (simply pass the whole object and forget).

To get different class types of that function. You would need to make a factory object, that will generate objects based on the list of fields (for example: dict with { some_unique_value_made_of_fields: class} )

This way I get a simple ORM.

red777
  • 354
  • 1
  • 3
  • 11