Можно ли хранить объекты класса Python в SQLite? - PullRequest
29 голосов
/ 12 января 2010

Я хотел бы хранить объекты Python в SQLite базе данных. Это возможно?

Если да, то какие будут ссылки / примеры для него?

Ответы [ 8 ]

53 голосов
/ 12 января 2010

Вы не можете сохранить сам объект в БД. То, что вы делаете - это сохраняете данные объекта и восстанавливаете их позже.

Хороший способ - использовать превосходную библиотеку SQLAlchemy . Это позволяет вам сопоставить ваш определенный класс с таблицей в базе данных. Каждый сопоставленный атрибут будет сохранен и может быть использован для восстановления объекта. Запрос к базе данных возвращает экземпляры вашего класса.

С ним вы можете использовать не только sqlite, но и большинство баз данных. В настоящее время он также поддерживает Postgres, MySQL, Oracle, MS-SQL, Firebird, MaxDB, MS Access, Sybase, Informix и IBM DB2. И вы можете попросить своего пользователя выбрать, какую из них он хочет использовать, потому что вы можете переключаться между этими базами данных, вообще не меняя код.

Есть также много интересных функций, таких как автоматическое JOIN s, полиморфирование ...

Быстрый простой пример, который вы можете запустить:

from sqlalchemy import Column, Integer, Unicode, UnicodeText, String
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

from random import choice
from string import letters

engine = create_engine('sqlite:////tmp/teste.db', echo=True)
Base = declarative_base(bind=engine)

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(40))
    address = Column(UnicodeText, nullable=True)
    password = Column(String(20))

    def __init__(self, name, address=None, password=None):
        self.name = name
        self.address = address
        if password is None:
            password = ''.join(choice(letters) for n in xrange(10))
        self.password = password

Base.metadata.create_all()

Session = sessionmaker(bind=engine)
s = Session()

Тогда я могу использовать это так:

# create instances of my user object
u = User('nosklo')
u.address = '66 Some Street #500'

u2 = User('lakshmipathi')
u2.password = 'ihtapimhskal'

# testing
s.add_all([u, u2])
s.commit()

Это будет запускать INSERT операторов для базы данных.

# When you query the data back it returns instances of your class:

for user in s.query(User):
    print type(user), user.name, user.password

Этот запрос будет выполняться SELECT users.id AS users_id, users.name AS users_name, users.address AS users_address, users.password AS users_password.

Напечатанный результат будет:

<class '__main__.User'> nosklo aBPDXlTPJs
<class '__main__.User'> lakshmipathi ihtapimhskal

Таким образом, вы эффективно храните свой объект в базе данных, как лучше.

13 голосов
/ 12 января 2010

Да, это возможно, но существуют разные подходы, и какой из них подходит, будет зависеть от ваших требований.

  • Травление

    Вы можете использовать модуль pickle для сериализации объектов, а затем сохранить эти объекты в BLOB-объекте в sqlite3 (или текстовом поле, если дамп, например, закодирован в base64). Помните о некоторых возможных проблемах: questions / 198692 / can-i-pickle-a-python-словарь-в-sqlite3-текстовое поле

  • Объектно-реляционная-Mapping

    Вы можете использовать объектное реляционное отображение. По сути, это создает «базу данных виртуальных объектов», которую можно использовать из языка программирования ( Wikipedia ). Для python есть хороший инструментарий для этого: sqlalchemy .

7 голосов
/ 12 января 2010

Вы можете использовать pickle.dumps , его возвращаемые выбираемые объекты в виде строк, вам не нужно записывать его во временные файлы.

Вернуть маринованное представление объект как строка вместо запись в файл.

import pickle

class Foo:
    attr = 'a class attr'

picklestring = pickle.dumps(Foo)
1 голос
/ 13 июля 2016

В зависимости от ваших конкретных потребностей, возможно, стоит заглянуть в Django (www.djangoproject.com) для выполнения этой задачи. Django на самом деле является веб-фреймворком, но одна из задач, которую он выполняет, - дать вам возможность определять модели как объекты Python (наследуя от базового класса, предоставляемого фреймворком) Затем он автоматически создаст таблицы базы данных, необходимые для хранения этих объектов, и sqlite входит в число поддерживаемых бэкэндов. Он также предоставляет удобные функции для запроса базы данных и возврата одного или нескольких подходящих объектов. Смотрите, например, документацию о моделях в django:

http://docs.djangoproject.com/en/1.9/topics/db/models/

Недостаток, конечно, в том, что вам нужно установить полноценный веб-фреймворк, и (насколько я помню) вы можете хранить только объекты, атрибуты которых поддерживаются django. Кроме того, он предназначен для хранения множества экземпляров предопределенных объектов, а не для хранения одного экземпляра каждого из множества различных объектов. В зависимости от ваших потребностей, это может или не может быть непрактичным.

1 голос
/ 12 января 2010

Другим выбором вместо травления является использование ORM .Это позволяет сопоставить строки в базе данных с объектом.См. http://wiki.python.org/moin/HigherLevelDatabaseProgramming для начальной точки.Я бы порекомендовал SQLAlchemy или SQLObject .

1 голос
/ 12 января 2010

Вы можете использовать pickle для сериализации объекта. Сериализованный объект может быть вставлен в базу данных sqlite как поле байтового массива.

f=open('object.dump', 'rw')
pickle.dump(obj, f)

Теперь прочитайте object.dump из файла и запишите его в базу данных sqlite. Возможно, вы захотите записать его как двоичный тип данных; Читайте о хранении двоичных данных и больших двоичных объектов в SQLite здесь . Обратите внимание, что согласно этому источнику , SQLite ограничивает размер такого поля данных до 1 МБ.

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

0 голосов
/ 13 марта 2013

Существует относительно простой способ хранить и сравнивать объекты, даже если их правильно индексировать и ограничивать (с помощью ubique) столбцы, содержащие объекты. И все это без использования двигателей ORM. Объекты должны храниться с использованием команды pickle dump (поэтому производительность может быть проблемой). Вот пример для хранения кортежей Python, ограничения индексации и сравнения. Этот метод может быть легко применен к любому другому классу 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)")


######################### Test ########################

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("select p from test where pycmp(p,?) >= 0", ((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()
0 голосов
/ 12 января 2010

Один из вариантов - использовать O / R mapper, например SQLObject. Он выполнит большую часть сантехники для сохранения объекта Python в базе данных и поддерживает SQLite. Как уже упоминалось в другом месте, вы также можете сериализовать объект, используя метод, например pickle, который выводит представление объекта, который он может восстановить, считывая и анализируя.

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