2013-05-02 33 views
9

我打算用python api for sqlite3,我有一个用于存储语言的小表,里面有一个id,name和creation_date字段。我试图将原始查询结果映射为namedtuple,正如文档所建议的那样,这样我可以以更易读的方式管理行,所以这里是我的namedtuple将结果行映射到Python中的namedtuple sqlite

LanguageRecord = namedtuple('LanguageRecord', 'id, name, creation_date') 

的文档表明该映射的代码如下:

for language in map(LanguageRecord._make, c.fetchall()): 
    # do something with languages 

这是罚款时,我想回到语言的集合,但在这种情况下,我想只是 检索一个语言:

c.execute('SELECT * FROM language WHERE name=?', (name,)) 

所以我的第一次尝试是这样的:

language = map(LanguageRecord._make, c.fetchone()) 

此代码不工作,因为fetchone()返回一个元组,而不是一个清单,一个元组, 所以map函数试图创建三个namedtuples一个每个元组领域的思想。

我的第一个办法来解决,这是明确创建一个列表,并追加到它的元组的结果,是这样的:

languages = [] 
languages.append(c.fetchone()) 
for language in map(LanguageRecord._make, languages): 
    # do something with language 

我的第二个方法是使用fetchall()虽然我只想一个记录。我可以在数据库中设置 名称字段以约束一个结果unique

for language in map(LanguageRecord._make, c.fetchall()): 
    # do something with languages 

另一种方法可以是使用fetchall()[0]没有unique约束到garantize只是一个结果。

我的问题是哪个是处理这个问题的最好和常见的方式,我应该总是使用fetchall来维护一个通用接口并让数据库管理唯一性逻辑?还是应该像方法1那样明确地创建一个列表?有没有更简单的方法来完成这项任务?

+0

你也可以遍历数据库游标,就没有必要获取所有记录,除非你想到,所以代码可以被重写为map(LanguageRecord._make,c)'。 – 2013-05-02 11:00:48

回答

19

有一种更简单的方法! Sqlite3为用户提供了一种定义"row factories"的方法。这些行工厂接受游标和元组行,并可以返回它想要的任何类型的对象。

一旦您设置的行工厂光标返回将应用于数组行的my_row_factory结果

con.row_factory = my_row_factory 

然后行。例如,

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

产生

LanguageRecord(id=1, name=2, creation_date=3) 

有关如何定义一个namedtuple工厂,参见this post另一个例子。


顺便说一句,如果你设置

conn.row_factory = sqlite3.Row 

再行返回类型的字典,它的键是表的列名。因此,您可以使用内建的sqlite3.Row行工厂,并通过row['creation_date']访问与之相对应的部分,而不是使用row.creation_date之类的东西访问指定的部件。

+1

'sqlite3.Row'不是一个真正的字典,因为它没有实现'.get()'或'.__ contains __()'。 – rgov 2017-04-10 17:28:35

0

我觉得使用起来更好 for language in map(LanguageRecord._make, c.fetchall()[:1]): 因为它可能会导致IndexError与fetchall()[0]。

如果您需要一个结果并且查询中已经有“WHERE”。据我所知,查询应该返回一行。早期的优化是邪恶的。 :)

1

一种改进row_factory其实这是,它可以用于各种查询的可重复使用:

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