Sqlite и Python — вернуть словарь с помощью fetchone()?
Вопрос
Я использую sqlite3 в Python 2.5.Я создал таблицу, которая выглядит следующим образом:
create table votes (
bill text,
senator_id text,
vote text)
Я получаю к нему доступ примерно так:
v_cur.execute("select * from votes")
row = v_cur.fetchone()
bill = row[0]
senator_id = row[1]
vote = row[2]
Что я хотел бы сделать, так это заставить fetchone (или какой-либо другой метод) возвращать словарь, а не список, чтобы я мог ссылаться на поле по имени, а не по позиции.Например:
bill = row['bill']
senator_id = row['senator_id']
vote = row['vote']
Я знаю, что вы можете сделать это с MySQL, но кто-нибудь знает, как это сделать с SQLite?
Спасибо!!!
Решение
Как я это делал раньше:
def dict_factory(cursor, row):
d = {}
for idx,col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
Затем вы настраиваете его в своем соединении:
from pysqlite2 import dbapi2 as sqlite
conn = sqlite.connect(...)
conn.row_factory = dict_factory
Это работает в pysqlite-2.4.1 и python 2.5.4.
Другие советы
На самом деле в sqlite3 есть такая возможность.Изменить row_factory
член объекта соединения с sqlite3.Row
:
conn = sqlite3.connect('db', row_factory=sqlite3.Row)
или
conn.row_factory = sqlite3.Row
Это позволит вам получить доступ к элементам строки по имени (словарному стилю) или по индексу.Это гораздо эффективнее, чем создавать собственное обходное решение.
Недавно я пытался сделать что-то подобное, используя sqlite3.Row().Хотя sqlite3.Row() отлично подходит для предоставления интерфейса, подобного словарю, или интерфейса, подобного кортежу, он не работал, когда я передал строку с помощью **kwargs.Итак, нужен был быстрый способ преобразования его в словарь.Я понял, что объект Row() можно преобразовать в словарь, просто используя itertools.
Питон 2:
db.row_factory = sqlite3.Row
dbCursor = db.cursor()
dbCursor.execute("SELECT * FROM table")
row = dbCursor.fetchone()
rowDict = dict(itertools.izip(row.keys(), row))
Или в Python 3, проще:
dbCursor = db.cursor()
dbCursor.execute("SELECT * FROM table")
row = dbCursor.fetchone()
rowDict = dict(zip([c[0] for c in dbCursor.description], row))
Аналогичным образом вы можете использовать команду dbCursor.fetchall() и преобразовать весь набор строк в список словарей в цикле for.
Конечно, создайте себе DictConnection и DictCursor, как описано и показано на http://trac.edgewall.org/pysqlite.org-mirror/wiki/PysqliteFactories например.
Я знаю, что вы об этом не спрашиваете, но почему бы просто не использовать sqlalchemy для создания формы для базы данных?тогда вы можете делать такие вещи, как,
entry = model.Session.query(model.Votes).first()
print entry.bill, entry.senator_id, entry.vote
В качестве дополнительного бонуса ваш код можно будет легко перенести в альтернативную базу данных, а соединениями и всем остальным можно будет управлять бесплатно.
Я использовал это:
def get_dict(sql):
return dict(c.execute(sql,()).fetchall())
Тогда вы можете сделать это:
c = conn.cursor()
d = get_dict("select user,city from vals where user like 'a%'");
Сейчас d
это словарь, в котором находятся ключи user
и значения city
.Это также работает для group by
Я использую что-то вроде этого:
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])
с этим:
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()
это класс, который наследуется от SqliteRow
.Класс SqliteRow — это базовый класс для каждого объекта, который я хочу вернуть по запросу.Каждый столбец становится атрибутом и регистрируется в fields
список.Функция to_tuple
используется для изменения всего объекта в форме, подходящей для запросов (просто передайте весь объект и забудьте).
Чтобы получить разные типы классов этой функции.Вам нужно будет создать фабричный объект, который будет генерировать объекты на основе списка полей (например:dict с {some_unique_value_made_of_fields:сорт} )
Таким образом я получаю простой ORM.