sqlite adapter and converter

在sqlite中,要將python的object存入sqlite,可以透過在class實作conform method,或者是透過sqlite提供的register_adapter,再者就是先將object轉換成sqlite有的type,在存入即可。不過透過以上的方式,其實實作邏輯都是相同,只有透過不同存取介面。

conform為例:

import sqlite3

class Point(object):
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __conform__(self, protocol):
        if protocol is sqlite3.PrepareProtocol:
            return "%f;%f" % (self.x, self.y)

con = sqlite3.connect(":memory:")
cur = con.cursor()

p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print cur.fetchone()[0]

point會將值轉成string,最後會輸出"4.000000;-3.200000",另外%f指的是浮點數。

透過register_adapter:

def adapt_point(point):
    return "%f;%f" % (point.x, point.y)

sqlite3.register_adapter(Point, adapt_point)

只要在connect之前註冊好adapter,point就會自動轉成定義後格式。

如果要將以存入的值,轉回原先的object,這時可透過converter

def convert_point(s):
    x, y = map(float, s.split(";"))
    return Point(x, y)

# Register the converter
sqlite3.register_converter("point", convert_point)

以上方式定義後,還必須在connect的時候,設定detect_types的參數,下面有3種方式。

第一種使用sqlite3.PARSE_DECLTYPES

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
cur = con.cursor()
cur.execute("create table test(p point)")

cur.execute("insert into test(p) values (?)", (p,))
cur.execute("select p from test")
print "with declared types:", cur.fetchone()[0]

必須要在create table的時候,就是先定義好point type,之後query出來會自訂轉成object。

第二種方式使用sqlite3.PARSE_COLNAMES

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)
cur = con.cursor()
cur.execute("create table test(p)")

cur.execute("insert into test(p) values (?)", (p,))
cur.execute('select p as "p [point]" from test')
print "with column names:", cur.fetchone()[0]

這種方式則是在query的時候,指定query欄位的type( p [point] )。

最後一種方式,就是兩種一起用:

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)