40

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

4

14 に答える 14

57

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

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

挿入/更新するには:

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

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

データを取得するには:

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

BLOB フィールドを取得するとき、sqlite3 は「buffer」python タイプを取得します。これは、loads メソッドに渡す前にstrを使用してストリニファイする必要があります。

于 2010-02-26T10:23:14.950 に答える
23

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

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

于 2008-10-13T19:31:36.213 に答える
5

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

于 2008-10-13T19:37:31.507 に答える
3

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

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

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

query = u'''insert into testtable VALUES(?)'''
b = sqlite3.Binary(binarydata)
cur.execute(query,(b,))
con.commit()
于 2008-10-14T06:07:06.167 に答える
2

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

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

于 2008-10-13T19:35:59.340 に答える
2

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

pickle できない辞書 (つまり、選択できないオブジェクトを含むもの) に注意してください。

于 2008-10-13T19:37:44.190 に答える
2

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

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

辞書には任意のネストされたデータ構造を含めることができるため、pickle できない場合があります。

于 2008-10-13T20:00:26.890 に答える
1

もう 1 つのオプションは、dict を保存し、ユーザーの「表示の喜び」のためにそれを吐き出すことが要件であることを考慮して、shelvepickleable データをファイルに永続化できるようにするモジュールを使用することです。Python ドキュメントはこちらです。

于 2008-10-13T23:13:39.073 に答える
1

オブジェクト データをピクル ダンプ、ジェイソンなどとして保存することは可能ですが、それらにインデックスを付けて制限し、それらのインデックスを使用する選択クエリを実行することもできます。これは、他の 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()
于 2013-03-13T12:07:17.880 に答える
1

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

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

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

于 2008-10-13T22:11:31.227 に答える
1

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

于 2008-10-14T00:34:57.163 に答える