将结果行映射到Python中的namedtuple sqlite
我打算用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那样明确地创建一个列表?有没有更简单的方法来完成这项任务?
有一种更简单的方法! 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
之类的东西访问指定的部件。
'sqlite3.Row'不是一个真正的字典,因为它没有实现'.get()'或'.__ contains __()'。 – rgov 2017-04-10 17:28:35
我觉得使用起来更好 for language in map(LanguageRecord._make, c.fetchall()[:1]):
因为它可能会导致IndexError与fetchall()[0]。
如果您需要一个结果并且查询中已经有“WHERE”。据我所知,查询应该返回一行。早期的优化是邪恶的。 :)
一种改进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()
你也可以遍历数据库游标,就没有必要获取所有记录,除非你想到,所以代码可以被重写为map(LanguageRecord._make,c)'。 – 2013-05-02 11:00:48