Могу ли я вставить словарь python в текстовое поле sqlite3?

#python #sqlite #persistence

#python #sqlite #pickle

Вопрос:

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

Комментарии:

1. Все зависит от того, что содержит ваш словарь. Кроме того, это звучит очень похоже на то, что вы делаете что-то злое. Каковы ваши причины использования базы данных? Каковы ваши причины выбора SQLite?

2. Хорошей новостью является то, что это для крошечного приложения, которое будет использоваться, самое большее, около 5 человек, и ему просто нужно сохранить некоторые данные и отправить их обратно. Идея pickle -> sqlite возникла после слишком большого количества горных росы, но мне было любопытно посмотреть, возможно ли это вообще.

Ответ №1:

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

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

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

 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']))
  

При получении поля большого двоичного объекта sqlite3 получает тип python ‘buffer’, который необходимо strinyfied с помощью str перед передачей в метод loads .

Комментарии:

1. Я люблю тебя, чувак! Это решило проблему, с которой я столкнулся с Redis! Я не указывал протокол, и хотя я не получал никаких ошибок удаления, я получал противоречивые данные, вероятно, из-за какой-то проблемы с кодировкой. Имеет ли это какой-либо смысл?

Ответ №2:

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

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

Комментарии:

1. Да, я знаю, что это немного сомнительный дизайн. Данные, о которых идет речь, никогда не нужно будет выбирать, их просто нужно сохранить, а затем отправить обратно для «удовольствия пользователя от просмотра». (Во всяком случае, это то, что мне говорит автор спецификации.)

2. Пока вы делаете это при условии, что это быстрое и грязное решение, а не думаете, что это действительно аккуратный и умный трюк, я думаю, все будет в порядке.

Ответ №3:

Я написал блог об этой идее, за исключением того, что вместо 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,))
''')
  

Ответ №4:

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

Ответ №5:

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

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

Вот несколько примеров кода:

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

Ответ №6:

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

Имейте в виду, однако, что ТЕКСТОВЫЕ поля в SQLite используют кодировку базы данных, поэтому вам может потребоваться преобразовать его в простую строку перед удалением.

Ответ №7:

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

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

Ответ №8:

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

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

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

Ответ №9:

SpoonMeiser верен, у вас должна быть веская причина для доступа к базе данных.

Нетрудно написать объекты Python, которые реализуют постоянство с помощью SQLite. Затем вы также можете использовать интерфейс командной строки SQLite для работы с данными. Что, по моему опыту, стоит дополнительной работы, поскольку многие функции отладки и администрирования можно просто выполнять из CLI, а не писать конкретный код на Python.

На ранних стадиях проекта я сделал то, что вы предлагаете, и в итоге переписал класс Python для каждого бизнес-объекта (примечание: я не сказал для каждой таблицы!) Таким образом, тело приложения может сосредоточиться на том, «что» нужно сделать, а не на том, «как» это делается.

Ответ №10:

Другой вариант, учитывая, что ваше требование состоит в том, чтобы сохранить dict, а затем вернуть его обратно для «удовольствия пользователя от просмотра», — это использовать shelve модуль, который позволит вам сохранять любые данные, подлежащие обработке, в файл. Документы python здесь.

Ответ №11:

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

Ответ №12:

Можно хранить данные объекта в виде дампа pickle, 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()
  

Ответ №13:

Многие приложения используют sqlite3 в качестве серверной части для SQLAlchemy, поэтому, естественно, этот вопрос можно задать и в рамках SQLAlchemy (именно так я столкнулся с этим вопросом).).

Для этого нужно было определить столбец, в котором желательно сохранить данные pickle для хранения данных «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, поскольку другие отмечали проблемы.)

Ответ №14:

Смотрите это решение в SourceForge:

y_serial.py модуль :: склад объектов Python с помощью SQLite

«Сериализация сохранение :: в нескольких строках кода сжимайте и аннотируйте объекты Python в SQLite; затем извлекайте их в хронологическом порядке по ключевым словам без какого-либо SQL. Самый полезный «стандартный» модуль для базы данных для хранения данных без схемы. «

http://yserial.sourceforge.net