Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Вставить/обновить:

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" "buffer", который необходимо использовать для strinyfied с помощью str, прежде чем передать его методу загрузки.

Ответ 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 имеет текстовые и двоичные форматы вывода. Если вы используете текстовый формат, вы можете сохранить его в поле TEXT, но он должен быть BLOB, если вы используете (более эффективный) двоичный формат.

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

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

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

Ответ 8

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

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

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

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

Ответ 9

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

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

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

Ответ 10

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

Ответ 11

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

Ответ 12

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

Ответ 13

Посмотрите это решение на SourceForge:

y_serial.py модуль:: хранилище объектов Python с SQLite

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

http://yserial.sourceforge.net

Ответ 14

Многие приложения используют 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, так как другие отмечали проблемы с этим.)