Можно ли вставить словарь Python в текстовое поле sqlite3? - PullRequest
34 голосов
/ 13 октября 2008

Есть какие-нибудь ошибки, о которых я должен знать? Могу ли я сохранить его в текстовом поле или мне нужно использовать блоб? (Я не слишком знаком с pickle или sqlite, поэтому я хотел убедиться, что я лаю правильное дерево с некоторыми из моих идей дизайна высокого уровня.)

Ответы [ 13 ]

46 голосов
/ 26 февраля 2010

Мне тоже нужно было достичь того же.

Оказывается, это вызвало у меня сильную головную боль, прежде чем я наконец понял, благодаря этому посту , как на самом деле заставить его работать в двоичном формате.

Для вставки / обновления:

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 получает тип буфера 'буфера', который необходимо подвергнуть строковому анализу с использованием str перед передачей в метод load.

17 голосов
/ 13 октября 2008

Если вы хотите сохранить маринованный объект, вам нужно использовать большой двоичный объект, так как это двоичные данные. Однако вы можете, скажем, base64 кодировать выбранный объект, чтобы получить строку, которая может быть сохранена в текстовом поле.

Как правило, подобные действия указывают на плохой дизайн, поскольку вы храните непрозрачные данные и теряете возможность использовать SQL для любых полезных манипуляций с этими данными. Хотя, не зная, что ты на самом деле делаешь, я не могу сделать моральный призыв к этому.

5 голосов
/ 12 января 2009

Я написал блог об этой идее, за исключением того, что вместо pickle я использовал json, так как хотел, чтобы он был совместим с 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,))
''')
3 голосов
/ 13 октября 2008

Pickle имеет как текстовый, так и двоичный форматы вывода. Если вы используете текстовый формат, вы можете сохранить его в поле TEXT, но это будет BLOB, если вы используете (более эффективный) двоичный формат.

2 голосов
/ 14 октября 2008

Я должен согласиться с некоторыми комментариями здесь. Будьте осторожны и убедитесь, что вы действительно хотите сохранить данные рассола в БД, возможно, есть лучший способ.

В любом случае в прошлом у меня были проблемы с попыткой сохранить двоичные данные в базе данных sqlite. Видимо, вам нужно использовать sqlite3.Binary () для подготовки данных для sqlite.

Вот пример кода:

query = u'''insert into testtable VALUES(?)'''
b = sqlite3.Binary(binarydata)
cur.execute(query,(b,))
con.commit()
2 голосов
/ 14 октября 2008

Да, вы можете сохранить маринованный объект в поле TEXT или BLOB в базе данных SQLite3, как объяснили другие.

Просто помните, что какой-то объект не может быть засолен . Встроенные типы контейнеров могут (dict, set, list, tuple и т. Д.). Но некоторые объекты, такие как дескрипторы файлов, ссылаются на состояние, которое является внешним по отношению к их собственным структурам данных, а другие типы расширений имеют аналогичные проблемы.

Так как словарь может содержать произвольные вложенные структуры данных, он может не поддерживать рассол.

2 голосов
/ 13 октября 2008

Если словарь можно выбрать, он также может быть сохранен в поле текста / блоба.

Просто будьте внимательны со словарями, которые невозможно засолить (иначе говоря, они содержат необратимые объекты).

2 голосов
/ 13 октября 2008

Так как Pickle может записать ваш граф объектов в строку, это должно быть возможно.

Имейте в виду, что поля TEXT в SQLite используют кодировку базы данных, поэтому вам может потребоваться преобразовать ее в простую строку перед тем, как отменить выбор.

1 голос
/ 13 марта 2013

Можно хранить данные объекта в виде дампов, джаза и т. Д., Но также можно индексировать их, ограничивать и запускать запросы на выборку, использующие эти индексы. Вот пример с кортежами, которые могут быть легко применены для любого другого класса 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 голос
/ 14 октября 2008

В зависимости от того, над чем вы работаете, вы можете заглянуть в модуль shove . Он делает нечто подобное, когда он автоматически сохраняет объекты Python в базе данных sqlite (и всевозможных других опциях) и притворяется словарём (как модуль shelve ).

...