SQLite e Python - retornar um dicionário usando fetchone ()?
Pergunta
Eu estou usando sqlite3 em python 2.5. Eu criei uma tabela que se parece com isso:
create table votes (
bill text,
senator_id text,
vote text)
Estou acessá-lo com algo parecido com isto:
v_cur.execute("select * from votes")
row = v_cur.fetchone()
bill = row[0]
senator_id = row[1]
vote = row[2]
O que eu gostaria de ser capaz de fazer é ter fetchone (ou algum outro método) retornar um dicionário, em vez de uma lista, para que eu possa se referir ao campo pelo nome, em vez de posição. Por exemplo:
bill = row['bill']
senator_id = row['senator_id']
vote = row['vote']
Eu sei que você pode fazer isso com o MySQL, mas alguém sabe como fazê-lo com SQLite?
Thanks !!!
Solução
A maneira que eu tenho feito isso no passado:
def dict_factory(cursor, row):
d = {}
for idx,col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
Em seguida, você configurá-lo em sua conexão:
from pysqlite2 import dbapi2 as sqlite
conn = sqlite.connect(...)
conn.row_factory = dict_factory
Isso funciona sob pysqlite-2.4.1 e python 2.5.4.
Outras dicas
Há realmente uma opção para isso no sqlite3. Altere o membro row_factory
do objeto de conexão para sqlite3.Row
:
conn = sqlite3.connect('db', row_factory=sqlite3.Row)
ou
conn.row_factory = sqlite3.Row
Isto irá permitir-lhe elementos de linha de acesso por nome - dicionário de estilo - ou pelo índice. Isso é muito mais eficiente do que criar o seu próprio trabalho-around.
Recentemente eu estava tentando fazer algo semelhante ao usar sqlite3.Row (). Enquanto sqlite3.Row () é ótimo para fornecer um dicionário-como interface ou uma tupla como interface, que não funcionou quando eu canalizada na linha usando kwargs **. Então, precisava de uma maneira rápida de convertê-lo em um dicionário. Compreendi que o objecto Fila () pode ser convertido a um dicionário simplesmente usando 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))
Ou em Python 3, mais simplesmente:
dbCursor = db.cursor()
dbCursor.execute("SELECT * FROM table")
row = dbCursor.fetchone()
rowDict = dict(zip([c[0] for c in dbCursor.description], row))
Da mesma forma, você pode usar o comando dbCursor.fetchall () e converter todo o conjunto de linhas a uma lista de dicionários em um loop.
Claro, tornar-se um DictConnection e DictCursor como explicado e mostrado em http: //trac.edgewall.org/pysqlite.org-mirror/wiki/PysqliteFactories por exemplo.
Eu sei que você não está pedindo isso, mas por que não usar sqlalchemy para construir um ORM para o banco de dados? então você pode fazer coisas como,
entry = model.Session.query(model.Votes).first()
print entry.bill, entry.senator_id, entry.vote
como um bônus adicional o seu código será facilmente transportável para um banco de dados alternativo, e as conexões e outros enfeites será gerido de forma gratuita.
Eu usei isso:
def get_dict(sql):
return dict(c.execute(sql,()).fetchall())
Em seguida, você pode fazer isso:
c = conn.cursor()
d = get_dict("select user,city from vals where user like 'a%'");
Agora d
é um dicionário onde as chaves são user
e os valores são city
. Isso também funciona para group by
Eu uso algo como isto:
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])
com este:
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()
é uma classe que herda de SqliteRow
.
classe SqliteRow é uma classe base para todos os objetos que eu quero ter retornado por uma consulta.
Cada coluna torna-se um atributo e é registrado na lista fields
.
to_tuple
função é usada para mudar todo o objeto para uma forma adequada para consultas (simplesmente passar todo o objeto e esquecer).
Para obter diferentes tipos de classe de tal função. Você precisaria fazer um objeto fábrica, que irá gerar objetos com base na lista de campos (por exemplo: dict com {some_unique_value_made_of_fields: class})
Desta forma, eu recebo um ORM simples.