使用fetchone()在Sqlite和Python中返回一个字典?

29

我正在使用 Python 2.5 中的 sqlite3。 我创建了一个看起来像这样的表:

   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中做到呢?

谢谢!!!


8个回答

76

实际上sqlite3中有一个选项可以实现此功能。将连接对象的row_factory成员更改为sqlite3.Row

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

这将允许您通过名称(类似于字典)或索引访问行元素。 这比创建自己的解决方法要高效得多。


3
这实际上是sqlite3模块文档中明确建议的做法:http://docs.python.org/library/sqlite3.html#row-objects - heltonbiker
4
使用sqlite3.Row时要小心,不能再使用row[1:3]语法,也不能将行生成器用作INSERT语句的输入。sqlite3.Row实际上是一个受损的实现。 - xApple
根据文档,应该是 conn = sqlite3.connect('db', factory=sqlite3.Row) 对吗? - andig
1
@andigпјҡдҪ иғҪз»ҷдёҖдёӘй“ҫжҺҘпјҢжҢҮеҗ‘дҪ жүҖжҸҗеҲ°зҡ„ж–ҮжЎЈеҗ—пјҹжҲ‘жҹҘзңӢзҡ„йӮЈдәӣж–ҮжЎЈиЎЁжҳҺжҲ‘们жӯЈеңЁеҲҶй…Қзҡ„connеҜ№иұЎжҲҗе‘ҳжҳҜrow_factoryгҖӮжҲ‘жғіе®ғеҸҜиғҪе·Із»Ҹж”№еҸҳдәҶпјӣжҜ•з«ҹжҲ‘еӣһзӯ”иҝҷдёӘй—®йўҳе·Із»Ҹеҝ«дёүе№ҙдәҶгҖӮ - Eric
@Eric:新手犯的错误——参考 http://docs.python.org/2/library/sqlite3.html 我看错了工厂,应该是行工厂而不是连接工厂 :( - andig
请注意,这并不返回一个实际的字典,因为问题要求不是这样。 - zr0gravity7

20

我之前处理这个问题的方式:

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下有效。


6
即使是快速而粗略的,row_factory钩子也是每个连接中最明智的方法。请注意,至少内置的sqlite3模块已经带有一个合适的行工厂:sqlite3.Row[http://docs.python.org/library/sqlite3.html#row-objects]。 - millimoose
谢谢!dict_factory() 方法也适用于 psycopg2 (postgres)。 - guettli

11

我最近尝试使用sqlite3.Row()做类似的事情。虽然sqlite3.Row()提供了类似字典或元组的接口,但是当我使用**kwargs来传递行时,它就不起作用了。所以,我需要一种快速将其转换为字典的方法。我意识到可以使用itertools简单地将Row()对象转换为字典。

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))

或者在 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循环中将整个行集转换为字典列表。


1
一个更简单的形式(适用于Python 3):dict(row) - Roland Bischof
1
dict(row) 依赖于行工厂返回可转换为字典的内容,这不是 DBAPI2 的要求,因此这里的示例更具可移植性。 - matt2000

5

这难道不比已接受的解决方案更好,后者看起来很不干净? - cregox
@Cawas,我同意你的观点,但原问题提出者似乎已经不在了,所以无法更改他一年前所选择的答案!-) - Alex Martelli
是的,我知道这就是SO的工作方式...我只是想确认一下是否真的更受欢迎。;-) - cregox
@Cawas:你可以使用你的投票来推荐这个答案,并沉淀那些不好的解决方案。 - Lie Ryan
问题在于该链接不再可用。 - PyNEwbie

2

我知道你并没有提出这个问题,但是为什么不直接使用SQLAlchemy来构建数据库的ORM呢?这样你就可以做到像下面这样的事情:


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

作为额外的福利,您的代码将轻松移植到另一个数据库,并且连接等内容将免费管理。

1
我用过这个:

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

你在 d 的结尾缺少了一个双引号吗? - Christopher Pearson

1

Simple solution, initialize a cursor object:

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

另一种选择:

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

代码的其余部分:

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

来源:mysql.connector.cursorMySQLdb.cursors.DictCursor

(注:mysql.connector.cursor 和 MySQLdb.cursors.DictCursor 是编程中与 MySQL 数据库交互时使用的两种不同的游标类型)


0
我使用类似这样的代码:
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 用于将整个对象更改为适合查询的形式(只需传递整个对象并忘记即可)。

要获取该函数的不同类类型,您需要创建一个工厂对象,该对象将根据字段列表生成对象(例如:具有 { some_unique_value_made_of_fields: class} 的字典)

这样我就得到了一个简单的 ORM。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接