web-dev-qa-db-ja.com

python辞書をsqlite3テキストフィールドにピクルスできますか?

知っておくべき落とし穴はありますか?テキストフィールドに保存できますか、それともblobを使用する必要がありますか? (私はpickleとsqliteのどちらにもあまり精通していないので、高レベルの設計アイデアのいくつかで適切なツリーを吠えていることを確認したかったのです。)

37
Electrons_Ahoy

ピクルス化されたオブジェクトを格納する場合は、バイナリデータであるため、blobを使用する必要があります。ただし、たとえば、base64でpickle化されたオブジェクトをエンコードして、テキストフィールドに格納できる文字列を取得できます。

ただし、一般的に、この種のことを行うと、設計が不適切であることを示します。不透明(OPAQUE)データを格納しているため、SQLを使用してそのデータに対して有用な操作を行うことができなくなります。あなたが実際に何をしているのかを知らなければ、私はそれについて道徳的な呼びかけをすることはできません。

20
SpoonMeiser

私も同じことを達成する必要がありました。

私が最終的に理解する前に、それが私にかなりの頭痛の種を引き起こしたことがわかりました、 この投稿のおかげで 、実際にそれをバイナリ形式で動作させる方法。

挿入/更新するには:

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

バイナリピクルスを強制するには、ダンプに2番目の引数を指定する必要があります。
また、sqlite3.BinaryをBLOBフィールドに収まるように注意してください。

データを取得するには:

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

BLOBフィールドを取得するとき、sqlite3は 'バッファ' pythonタイプを取得します。これは、前にstrを使用して制限する必要がありますロードメソッドに渡されます。

48
Benoit Vidis

私はこのアイデアについてブログを書きましたが、Perlや他のプログラムと相互運用できるようにしたかったので、ピクルスの代わりにjsonを使用しました。

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,))
''')
7
Gregg Lind

Pickleには、テキストとバイナリの両方の出力形式があります。テキストベースの形式を使用する場合は、TEXTフィールドに格納できますが、(より効率的な)バイナリ形式を使用する場合はBLOBである必要があります。

3
John Millikin

Pickleはオブジェクトグラフを文字列にダンプできるので、それは可能であるはずです。

ただし、SQLiteのTEXTフィールドはデータベースエンコーディングを使用するため、選択を解除する前に単純な文字列に変換する必要がある場合があることに注意してください。

辞書をピクルス化できる場合は、テキスト/ブロブフィールドにも保存できます。

酸洗いできない辞書(別名、酸洗いできないオブジェクトが含まれている辞書)に注意してください。

2
kender

はい、他の人が説明しているように、ピクルス化されたオブジェクトをSQLite3データベースのTEXTまたはBLOBフィールドに格納できます。

一部のオブジェクトピクルスにできないであることに注意してください。組み込みのコンテナータイプには、(dict、set、list、Tupleなど)があります。ただし、ファイルハンドルなどの一部のオブジェクトは、独自のデータ構造の外部にある状態を参照し、他の拡張タイプにも同様の問題があります。

ディクショナリには任意のネストされたデータ構造を含めることができるため、ピクルス化できない場合があります。

2
Dan Lenski

ここでのコメントのいくつかに同意する必要があります。注意して、ピクルスデータをデータベースに本当に保存したいことを確認してください。おそらくもっと良い方法があります。

いずれにせよ、私は過去にsqliteデータベースにバイナリデータを保存しようとして問題を抱えていました。どうやら、sqlite3.Binary()を使用してsqliteのデータを準備する必要があります。

サンプルコードは次のとおりです。

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

SpoonMeiserは正しいので、データベースにピクルスする強い理由が必要です。

SQLiteで永続性を実装するPythonオブジェクトを作成することは難しくありません。その後、SQLite CLIを使用してデータをいじることもできます。私の経験では、これは追加の作業の価値があります。多くのデバッグおよび管理機能は、特定のPythonコードを記述するのではなく、CLIから簡単に実行できます。

プロジェクトの初期段階で、私はあなたが提案したことを行い、最終的に各ビジネスオブジェクトのPythonクラス(注:各テーブルについては言いませんでした!))で書き直しました。アプリケーションの本体が、「どのように」実行されるのではなく、「何を」実行する必要があるかに焦点を当てることができる方法。

1
CyberFonic

オブジェクトデータをpickledump、jasonなどとして保存することは可能ですが、それらにインデックスを付け、制限し、それらのインデックスを使用するselectクエリを実行することもできます。これはタプルの例で、他の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()
1
pervlad

作業内容によっては、 shove モジュールを調べることをお勧めします。 Pythonオブジェクトをsqliteデータベース(およびその他のあらゆる種類のオプション)内に自動保存し、辞書のふりをします( shelve のように)。 =モジュール)。

1
Matthew

もう1つのオプションは、dictを保存してから、ユーザーの「閲覧の喜び」のためにそれを吐き出すことであると考えると、shelveモジュールを使用して、選択可能なデータをファイルに保持できるようにすることです。 pythonドキュメントは ここ です。

1
mhawke

多くのアプリケーションはSQLAlchemyのバックエンドとしてsqlite3を使用しているため、当然、この質問はSQLAlchemyフレームワークでも行うことができます(これが私がこの質問に出くわした方法です)。

これを行うには、「PickleType」データを格納するためにpickleデータを格納する列を定義する必要があります。実装は非常に簡単です。

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

(他の人が問題を指摘しているように、この例がピクルスの使用に最適であるとは主張していません。)

0
jbplasma

SourceForgeでこのソリューションを参照してください。

y_serial.pyモジュール::ウェアハウスPython SQLiteを使用したオブジェクト

「シリアル化+永続性::数行のコードで、PythonオブジェクトをSQLiteに圧縮して注釈を付けます。その後、SQLを使用せずにキーワードで時系列に取得します。データベースに最も役立つ「標準」モジュールスキーマのないデータを保存します。」

http://yserial.sourceforge.net

0
code43