是否可以在SQLite中存储Python类对象?

时间:2010-01-12 09:17:47

标签: python sqlite serialization

我想将Python对象存储到SQLite数据库中。这可能吗?

如果是这样的话会有什么链接/示例?

10 个答案:

答案 0 :(得分:53)

您无法将对象本身存储在数据库中。你所做的是存储来自对象的数据并在以后重建它。

一个好方法是使用优秀的SQLAlchemy库。它允许您将定义的类映射到数据库中的表。每个映射的属性都将被存储,并可用于重建对象。查询数据库会返回类的实例。

有了它,您不仅可以使用sqlite,还可以使用大多数数据库 - 它目前还支持Postgres,MySQL,Oracle,MS-SQL,Firebird,MaxDB,MS Access,Sybase,Informix和IBM DB2。并且您可以让您的用户选择她想要使用的那个,因为您基本上可以在这些数据库之间切换而无需更改代码。

还有很多很酷的功能 - 比如自动JOIN,多态......

您可以运行的简单快速示例:

from sqlalchemy import Column, Integer, Unicode, UnicodeText, String
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

from random import choice
from string import letters

engine = create_engine('sqlite:////tmp/teste.db', echo=True)
Base = declarative_base(bind=engine)

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(40))
    address = Column(UnicodeText, nullable=True)
    password = Column(String(20))

    def __init__(self, name, address=None, password=None):
        self.name = name
        self.address = address
        if password is None:
            password = ''.join(choice(letters) for n in xrange(10))
        self.password = password

Base.metadata.create_all()

Session = sessionmaker(bind=engine)
s = Session()

然后我可以像这样使用它:

# create instances of my user object
u = User('nosklo')
u.address = '66 Some Street #500'

u2 = User('lakshmipathi')
u2.password = 'ihtapimhskal'

# testing
s.add_all([u, u2])
s.commit()

这将针对数据库运行INSERT语句。

# When you query the data back it returns instances of your class:

for user in s.query(User):
    print type(user), user.name, user.password

该查询将运行SELECT users.id AS users_id, users.name AS users_name, users.address AS users_address, users.password AS users_password

打印结果如下:

<class '__main__.User'> nosklo aBPDXlTPJs
<class '__main__.User'> lakshmipathi ihtapimhskal

所以你有效地将你的对象存储到数据库中,这是最好的方法。

答案 1 :(得分:13)

是的,这是可能的,但有不同的方法,哪一个是合适的方法,将取决于您的要求。

答案 2 :(得分:7)

您可以使用pickle.dumps,其返回的可选对象作为字符串,您不需要将其写入临时文件。

  

返回腌制表示   该对象为字符串,而不是   把它写到文件中。

import pickle

class Foo:
    attr = 'a class attr'

picklestring = pickle.dumps(Foo)

答案 3 :(得分:1)

您可以使用pickle序列化对象。序列化对象可以作为bytearray字段插入sqlite DB。

f=open('object.dump', 'rw')
pickle.dump(obj, f)

现在从文件中读取object.dump,并将其写入sqlite DB。您可能希望将其写为二进制数据类型;阅读有关在SQLite here中存储二进制数据和blob的信息。请注意,根据this source,SQLite将此类数据字段的大小限制为1Mb。

我认为更好的选择是将对象序列化为文件,并在数据库中保留文件 name ,而不是内容。

答案 4 :(得分:1)

您选择 ORM 而不是酸洗。这使您可以将数据库中的行映射到对象。请参阅http://wiki.python.org/moin/HigherLevelDatabaseProgramming了解起点。我建议SQLAlchemySQLObject

答案 5 :(得分:1)

根据您的具体需求,可能值得研究Django(www.djangoproject.com)来完成这项任务。 Django实际上是一个Web框架,但它处理的任务之一是允许您将Models定义为python对象(继承自框架提供的基类)。然后它将自动创建存储这些对象所需的数据库表,sqlite是受支持的后端之一。它还提供了方便的函数来查询数据库并返回一个或多个匹配的对象。例如,请参阅django中有关模型的文档:

http://docs.djangoproject.com/en/1.9/topics/db/models/

缺点当然是你必须安装一个完整的Web框架,并且(据我记得)你只能存储django支持其属性的对象。此外,它用于存储预定义对象的许多实例,而不是用于存储许多不同对象中的每一个的一个实例。根据您的需要,这可能是也可能不是不切实际。

答案 6 :(得分:1)

SQLite 3 的适配器和转换器

我很惊讶没有人阅读 SQLite 3 库的文档,因为它说您可以通过创建适配器和转换器来做到这一点。例如,假设我们有一个名为“Point”的类,我们想要存储它,并在选择它并使用数据库游标的 fetchone 方法返回它时返回它。让模块知道你从数据库中选择的是一个点

from sqlite3 import connect, register_adaptor, register_converter

class Point:
def __init__(self, x, y):
    self.x, self.y = x, y
def __repr__(self):
    return "(%f;%f)" % (self.x, self.y)

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

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

# Register the adapter
register_adapter(Point, adapt_point)

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

p = Point(4.0, -3.2)

# 1) Using declared types
con = connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
con.execute("create table test(p point)")
con.execute("insert into test(p) values (?)", (p,))
cur = con.execute("select p from test")
print("with declared types:", cur.fetchone()[0])
con.close()

# 1) Using column names
con = connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)
con.execute("create table test(p)")
con.execute("insert into test(p) values (?)", (p,))
cur = con.execute('select p as "p [point]" from test')
print("with column names:", cur.fetchone()[0])
con.close()

答案 7 :(得分:0)

一种选择是使用像SQLObject.这样的O / R映射器。它将执行大部分管道工作以将Python对象持久化到数据库,并且它支持SQLite。正如其他地方所提到的,你也可以使用pickle等方法对对象进行序列化,这样可以通过回读和解析来转储它可以重建的对象的表示。

答案 8 :(得分:0)

存储和比较对象的方法比较简单,eaven可以正确地索引这些对象,并限制(使用ubique)包含对象的列。所有这些都没有使用ORM引擎。使用pickle转储存储对象桅杆(因此性能可能是个问题)以下是存储python元组,索引限制和比较的示例。此方法可以轻松应用于任何其他python类。所有需要的都在python sqlite3文档中解释(有人已发布链接)。无论如何,在以下示例中将它们全部放在一起:

import sqlite3
import pickle

def adapt_tuple(tuple):
    return pickle.dumps(tuple)    

sqlite3.register_adapter(tuple, adapt_tuple)    #cannot use pickle.dumps directly because of inadequate argument signature 
sqlite3.register_converter("tuple", pickle.loads)

def collate_tuple(string1, string2):
    return cmp(pickle.loads(string1), pickle.loads(string2))

# 1) Using declared types
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)

con.create_collation("cmptuple", collate_tuple)

cur = con.cursor()
cur.execute("create table test(p tuple unique collate cmptuple) ")
cur.execute("create index tuple_collated_index on test(p collate cmptuple)")


######################### Test ########################

cur.execute("select name, type  from sqlite_master") # where type = 'table'")
print(cur.fetchall())

p = (1,2,3)
p1 = (1,2)

cur.execute("insert into test(p) values (?)", (p,))
cur.execute("insert into test(p) values (?)", (p1,))
cur.execute("insert into test(p) values (?)", ((10, 1),))
cur.execute("insert into test(p) values (?)", (tuple((9, 33)) ,))
cur.execute("insert into test(p) values (?)", (((9, 5), 33) ,))

try:
    cur.execute("insert into test(p) values (?)", (tuple((9, 33)) ,))
except Exception as e:
    print e

cur.execute("select p from test order by p")
print "\nwith declared types and default collate on column:"
for raw in cur:
    print raw

cur.execute("select p from test order by p collate cmptuple")
print "\nwith declared types collate:"
for raw in cur:
    print raw

con.create_function('pycmp', 2, cmp)

print "\nselect grater than using cmp function:"
cur.execute("select p from test where pycmp(p,?) >= 0", ((10, ),) )
for raw in cur:
    print raw

cur.execute("select p from test where pycmp(p,?) >= 0", ((3,)))
for raw in cur:
    print raw 

print "\nselect grater than using collate:"
cur.execute("select p from test where p > ?", ((10,),) )
for raw in cur:
    print raw  

cur.execute("explain query plan select p from test where p > ?", ((3,)))
for raw in cur:
    print raw

cur.close()
con.close()

答案 9 :(得分:0)

正如其他人所提到的,答案是肯定的……但是该对象需要首先被序列化。我是一个名为klepto的软件包的作者,该软件包旨在将python对象无缝存储在SQL数据库,HDF存档和其他类型的键值存储中。

它提供了一个简单的字典界面,如下所示:

>>> from klepto.archives import sqltable_archive as sql_archive
>>> d = sql_archive(cached=False)
>>> d['a'] = 1  
>>> d['b'] = '1'
>>> d['c'] = min
>>> squared = lambda x:x*x
>>> d['d'] = squared
>>> class Foo(object):
...   def __init__(self, x):
...     self.x = x
...   def __call__(self):
...     return squared(self.x)
... 
>>> f = Foo(2)
>>> d['e'] = Foo
>>> d['f'] = f
>>> 
>>> d
sqltable_archive('sqlite:///:memory:?table=memo' {'a': 1, 'b': '1', 'c': <built-in function min>, 'd': <function <lambda> at 0x10f631268>, 'e': <class '__main__.Foo'>, 'f': <__main__.Foo object at 0x10f63d908>}, cached=False)
>>> 
>>> # min(squared(2), 1)
>>> d['c'](d['f'](), d['a'])
1
>>> 

存档构造函数中的cached关键字表示您是要使用本地内存缓存,还是将存档设置为缓存后端(cached=True),还是直接使用存档({{1 }}。在幕后,它可以使用cached=Falsepicklejson或其他序列化程序来腌制对象。查看档案的内部结构,您可以看到它正在利用dill

SQLAlchemy