我可以将 python 字典pickle到sqlite3文本字段中吗?

发布于 2024-07-07 18:06:45 字数 104 浏览 6 评论 0原文

有什么我应该注意的问题吗? 我可以将其存储在文本字段中,还是需要使用 blob? (我对 pickle 或 sqlite 都不太熟悉,所以我想确保我用我的一些高级设计思想找到了正确的方向。)

Any gotchas I should be aware of? Can I store it in a text field, or do I need to use a blob?
(I'm not overly familiar with either pickle or sqlite, so I wanted to make sure I'm barking up the right tree with some of my high-level design ideas.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

长途伴 2024-07-14 18:06:45

我也需要实现同样的目标。

事实证明,在我最终弄清楚之前,它让我相当头痛, 感谢这篇文章,如何实际使其以二进制格式工作。

要插入/更新:

pdata = cPickle.dumps(data, cPickle.HIGHEST_PROTOCOL)
curr.execute("insert into table (data) values (:data)", sqlite3.Binary(pdata))

您必须指定转储的第二个参数以强制进行二进制酸洗。
另请注意 sqlite3.Binary 以使其适合 BLOB 字段。

检索数据:

curr.execute("select data from table limit 1")
for row in curr:
  data = cPickle.loads(str(row['data']))

检索 BLOB 字段时,sqlite3 获取一个“缓冲区”python 类型,在传递给 load 方法之前需要使用 str 对其进行 strinyfied。

I needed to achieve the same thing too.

I turns out it caused me quite a headache before I finally figured out, thanks to this post, how to actually make it work in a binary format.

To insert/update:

pdata = cPickle.dumps(data, cPickle.HIGHEST_PROTOCOL)
curr.execute("insert into table (data) values (:data)", sqlite3.Binary(pdata))

You must specify the second argument to dumps to force a binary pickling.
Also note the sqlite3.Binary to make it fit in the BLOB field.

To retrieve data:

curr.execute("select data from table limit 1")
for row in curr:
  data = cPickle.loads(str(row['data']))

When retrieving a BLOB field, sqlite3 gets a 'buffer' python type, that needs to be strinyfied using str before being passed to the loads method.

枕头说它不想醒 2024-07-14 18:06:45

如果要存储 pickle 对象,则需要使用 blob,因为它是二进制数据。 但是,您可以对 pickled 对象进行 base64 编码以获得可存储在文本字段中的字符串。

不过,一般来说,这样做表明设计很糟糕,因为您存储的是不透明的数据,因此您失去了使用 SQL 对该数据进行任何有用操作的能力。 尽管不知道你实际上在做什么,但我无法真正对此做出道德呼吁。

If you want to store a pickled object, you'll need to use a blob, since it is binary data. However, you can, say, base64 encode the pickled object to get a string that can be stored in a text field.

Generally, though, doing this sort of thing is indicative of bad design, since you're storing opaque data you lose the ability to use SQL to do any useful manipulation on that data. Although without knowing what you're actually doing, I can't really make a moral call on it.

唯憾梦倾城 2024-07-14 18:06:45

我写了一篇关于这个想法的博客,除了使用 json 代替 pickle 之外,因为我希望它能够与 perl 和其他程序互操作。

http://writeonly。 wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/

从架构上来说,这是一种快速而肮脏的方式来获取任意的持久性、事务等。数据结构。 我发现当我想要持久性并且不需要在 sql 层中对数据做太多操作时(或者在 sql 中处理起来非常复杂,而在生成器中处理起来很简单),这种组合非常有用。

代码本身非常简单:

#  register the "loader" to get the data back out.
sqlite3.register_converter("pickle", cPickle.loads) 

然后,当您想将其转储到数据库中时,

p_string = p.dumps( dict(a=1,b=[1,2,3]))  
conn.execute(''' 
   create table snapshot( 
      id INTEGER PRIMARY KEY AUTOINCREMENT, 
        mydata pickle); 
''')  

conn.execute(''' 
    insert into snapshot values 
    (null, ?)''', (p_string,))
''')

I wrote a blog about this idea, except instead of a pickle, I used json, since I wanted it to be interoperable with perl and other programs.

http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/

Architecturally, this is a quick and dirty way to get persistence, transactions, and the like for arbitrary data structures. I have found this combination to be really useful when I want persistence, and don't need to do much in the sql layer with the data (or it's very complex to deal with in sql, and simple with generators).

The code itself is pretty simple:

#  register the "loader" to get the data back out.
sqlite3.register_converter("pickle", cPickle.loads) 

Then, when you want to dump it into the db,

p_string = p.dumps( dict(a=1,b=[1,2,3]))  
conn.execute(''' 
   create table snapshot( 
      id INTEGER PRIMARY KEY AUTOINCREMENT, 
        mydata pickle); 
''')  

conn.execute(''' 
    insert into snapshot values 
    (null, ?)''', (p_string,))
''')
过潦 2024-07-14 18:06:45

Pickle 具有文本和二进制输出格式。 如果您使用基于文本的格式,则可以将其存储在 TEXT 字段中,但如果您使用(更有效的)二进制格式,则它必须是 BLOB。

Pickle has both text and binary output formats. If you use the text-based format you can store it in a TEXT field, but it'll have to be a BLOB if you use the (more efficient) binary format.

唔猫 2024-07-14 18:06:45

我必须同意这里的一些评论。 请小心并确保您确实想要将 pickle 数据保存在数据库中,可能有更好的方法。

无论如何,我过去在尝试将二进制数据保存在 sqlite 数据库中时遇到了麻烦。
显然你必须使用 sqlite3.Binary() 来为 sqlite 准备数据。

这是一些示例代码:

query = u'''insert into testtable VALUES(?)'''
b = sqlite3.Binary(binarydata)
cur.execute(query,(b,))
con.commit()

I have to agree with some of the comments here. Be careful and make sure you really want to save pickle data in a db, there's probably a better way.

In any case I had trouble in the past trying to save binary data in the sqlite db.
Apparently you have to use the sqlite3.Binary() to prep the data for sqlite.

Here's some sample code:

query = u'''insert into testtable VALUES(?)'''
b = sqlite3.Binary(binarydata)
cur.execute(query,(b,))
con.commit()
愚人国度 2024-07-14 18:06:45

由于 Pickle 可以将对象图转储到字符串中,因此应该是可能的。

请注意,尽管 SQLite 中的 TEXT 字段使用数据库编码,因此您可能需要在取消 pickle 之前将其转换为简单的字符串。

Since Pickle can dump your object graph to a string it should be possible.

Be aware though that TEXT fields in SQLite uses database encoding so you might need to convert it to a simple string before you un-pickle.

○闲身 2024-07-14 18:06:45

如果字典可以被 pickle,它也可以存储在 text/blob 字段中。

只需要注意无法pickle的字典(又名包含无法pickle的对象)。

If a dictionary can be pickled, it can be stored in text/blob field as well.

Just be aware of the dictionaries that can't be pickled (aka that contain unpickable objects).

一紙繁鸢 2024-07-14 18:06:45

是的,您可以将 pickled 对象存储在 SQLite3 数据库的 TEXT 或 BLOB 字段中,正如其他人所解释的那样。

请注意,某些对象无法腌制。 内置的容器类型可以(dict、set、list、tuple等)。 但某些对象(例如文件句柄)引用其自身数据结构外部的状态,而其他扩展类型也有类似的问题。

由于字典可以包含任意嵌套数据结构,因此它可能无法进行pickle。

Yes, you can store a pickled object in a TEXT or BLOB field in an SQLite3 database, as others have explained.

Just be aware that some object cannot be pickled. The built-in container types can (dict, set, list, tuple, etc.). But some objects, such as file handles, refer to state that is external to their own data structures, and other extension types have similar problems.

Since a dictionary can contain arbitrary nested data structures, it might not be pickle-able.

一抹微笑 2024-07-14 18:06:45

SpoonMeiser 是正确的,您需要有充分的理由将其放入数据库。

编写使用 SQLite 实现持久性的 Python 对象并不困难。 然后您也可以使用 SQLite CLI 来处理数据。 根据我的经验,这值得额外的工作,因为许多调试和管理功能可以简单地从 CLI 执行,而不是编写特定的 Python 代码。

在项目的早期阶段,我按照您的建议进行了操作,最终为每个业务对象重写了一个 Python 类(注意:我没有说每个表!)这样应用程序的主体就可以专注于需要“做什么”而不是“如何”完成。

SpoonMeiser is correct, you need to have a strong reason to pickle into a database.

It's not difficult to write Python objects that implement persistence with SQLite. Then you can use the SQLite CLI to fiddle with the data as well. Which in my experience is worth the extra bit of work, since many debug and admin functions can be simply performed from the CLI rather than writing specific Python code.

In the early stages of a project, I did what you propose and ended up re-writing with a Python class for each business object (note: I didn't say for each table!) This way the body of the application can focus on "what" needs to be done rather than "how" it is done.

听你说爱我 2024-07-14 18:06:45

考虑到您的要求是保存一个字典,然后将其吐出来以供用户“观看乐趣”,另一种选择是使用 shelve 模块,它可以让您将任何可腌制的数据保存到文件中。 Python 文档位于此处

The other option, considering that your requirement is to save a dict and then spit it back out for the user's "viewing pleasure", is to use the shelve module which will let you persist any pickleable data to file. The python docs are here.

嗫嚅 2024-07-14 18:06:45

根据您正在处理的内容,您可能需要查看 shove 模块。 它做了类似的事情,它在 sqlite 数据库(以及各种其他选项)中自动存储 Python 对象,并假装是一本字典(就像 搁置模块)。

Depending on what you're working on, you might want to look into the shove module. It does something similar, where it auto-stores Python objects inside a sqlite database (and all sorts of other options) and pretends to be a dictionary (just like the shelve module).

吃颗糖壮壮胆 2024-07-14 18:06:45

可以将对象数据存储为 pickle dump、jason 等,但也可以对它们进行索引、限制它们并运行使用这些索引的选择查询。 这是元组的示例,可以轻松应用于任何其他 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)")

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("explain query plan select p from test where p > ?", ((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()

It is possible to store object data as pickle dump, jason etc but it is also possible to index, them, restrict them and run select queries that use those indices. Here is example with tuples, that can be easily applied for any other python class. All that is needed is explained in python sqlite3 documentation (somebody already posted the link). Anyway here it is all put together in the following example:

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

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("explain query plan select p from test where p > ?", ((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()
从来不烧饼 2024-07-14 18:06:45

许多应用程序使用 sqlite3 作为 SQLAlchemy 的后端,因此,自然地,这个问题也可以在 SQLAlchemy 框架中提出(这就是我遇到这个问题的方式)。

为此,需要定义需要存储泡菜数据的列来存储“PickleType”数据。 实现非常简单:(

from sqlalchemy import PickleType, Integer
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
import pickle

Base= declarative_base()

class User(Base):
    __tablename__= 'Users'

    id= Column(Integer, primary_key= True)
    user_login_data_array= Column(PickleType)

login_information= {'User1':{'Times': np.arange(0,20),
                             'IP': ['123.901.12.189','123.441.49.391']}}

engine= create_engine('sqlite:///memory:',echo= False) 

Base.metadata.create_all(engine)
Session_maker= sessionmaker(bind=engine)
Session= Session_maker()

# The pickling here is very intuitive! Just need to have 
# defined the column "user_login_data_array" to take pickletype data.

pickled_login_data_array= pickle.dumps(login_information)
user_object_to_add= User(user_login_data_array= pickled_login_data_array)

Session.add(user_object_to_add)
Session.commit()

我并不是说这个示例最适合使用 pickle,正如其他人指出的那样。)

Many applications use sqlite3 as a backend for SQLAlchemy so, naturally, this question can be asked in the SQLAlchemy framework as well (which is how I came across this question).

To do this, one will have wanted to define the column in which the pickle data is desired to be stored to store "PickleType" data. The implementation is pretty straightforward:

from sqlalchemy import PickleType, Integer
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
import pickle

Base= declarative_base()

class User(Base):
    __tablename__= 'Users'

    id= Column(Integer, primary_key= True)
    user_login_data_array= Column(PickleType)

login_information= {'User1':{'Times': np.arange(0,20),
                             'IP': ['123.901.12.189','123.441.49.391']}}

engine= create_engine('sqlite:///memory:',echo= False) 

Base.metadata.create_all(engine)
Session_maker= sessionmaker(bind=engine)
Session= Session_maker()

# The pickling here is very intuitive! Just need to have 
# defined the column "user_login_data_array" to take pickletype data.

pickled_login_data_array= pickle.dumps(login_information)
user_object_to_add= User(user_login_data_array= pickled_login_data_array)

Session.add(user_object_to_add)
Session.commit()

(I'm not claiming that this example would best be suited to use pickle, as others have noted issues with.)

独﹏钓一江月 2024-07-14 18:06:45

请参阅 SourceForge 上的此解决方案:

y_serial.py 模块 :: 使用 SQLite 仓库 Python 对象

“序列化 + 持久化 :: 用几行代码,将 Python 对象压缩并注释到 SQLite 中;然后按时间顺序检索它们,无需任何 SQL。大多数数据库存储无模式数据的有用“标准”模块。”

http://yserial.sourceforge.net

See this solution at SourceForge:

y_serial.py module :: warehouse Python objects with SQLite

"Serialization + persistance :: in a few lines of code, compress and annotate Python objects into SQLite; then later retrieve them chronologically by keywords without any SQL. Most useful "standard" module for a database to store schema-less data."

http://yserial.sourceforge.net

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文