2010-01-12 13 views

risposta

44

Non è possibile memorizzare l'oggetto stesso nel DB. Quello che fai è memorizzare i dati dall'oggetto e ricostruirlo in seguito.

Un buon modo è utilizzare l'eccellente libreria SQLAlchemy. Ti consente di mappare la tua classe definita su una tabella nel database. Ogni attributo mappato verrà memorizzato e può essere utilizzato per ricostruire l'oggetto. Interrogare il database restituisce le istanze della tua classe.

Con esso è possibile utilizzare non solo sqlite, ma la maggior parte dei database. Attualmente supporta anche Postgres, MySQL, Oracle, MS-SQL, Firebird, MaxDB, MS Access, Sybase, Informix e IBM DB2. E puoi chiedere all'utente di scegliere quale utilizzare, perché puoi passare da un database all'altro senza dover modificare il codice.

Ci sono anche un sacco di funzioni interessanti - come automatiche JOIN s, polymorphing ...

Un rapido, semplice esempio è possibile eseguire:

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() 

allora posso usare in questo modo:

# 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() 

Questo eseguirà le dichiarazioni INSERT rispetto al database.

# 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 

Quella query verrà eseguita SELECT users.id AS users_id, users.name AS users_name, users.address AS users_address, users.password AS users_password.

Il risultato stampato sarebbe:

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

Quindi stai in modo efficace la memorizzazione oggetto nel database, il modo migliore.

+0

In primo luogo, grazie a tutti per le vostre risposte/guida/suggerimenti !!! e @ nosklo, grazie codice di esempio ha funzionato come un fascino :) Grazie mille. Esplorerò di più su sqlalchemy con il tuo esempio: sembra che soddisferà il mio requisito ... grazie ancora a tutti. –

+0

In primo luogo, grazie a tutti per le vostre risposte/guida/suggerimenti !!! e @ nosklo, grazie codice di esempio ha funzionato come un fascino :) Grazie mille. Esplorerò di più su sqlalchemy con il tuo esempio: sembra che soddisferà le mie esigenze più che sottaceti ... grazie ancora a tutti. –

+1

Sì, il sottaceto IMHO è ** non ** ne vale la pena. Sembra bello e tutto, ma tu ** non puoi ** filtrare/unire/aggregare dati poiché l'oggetto è memorizzato come un * blob *, vanificando lo scopo di usare un database al primo posto. – nosklo

1

È possibile utilizzare pickle per serializzare l'oggetto. L'oggetto serializzato può essere inserito nel DB sqlite come campo per attiredray.

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

Ora leggere object.dump dal file, e scrivere al DB SQLite. Potresti volerlo scrivere come tipo di dati binari; leggi informazioni sulla memorizzazione di dati binari e BLOB in SQLite here. Si noti che in base a this source, SQLite limita la dimensione di tale datafield a 1Mb.

Penso che un'opzione migliore sarebbe serializzare l'oggetto in un file e mantenere il file nome, non contenuto, nel database.

+0

Questo è lontano da una buona pratica. La memorizzazione di oggetti decapitati come BLOB in un database sovverte il ragionamento per l'utilizzo di un database, la ricerca. memorizzare i nomi di file nel database a causa delle restrizioni sulle dimensioni dei file non migliora la situazione. – devsnd

0

Un'opzione consiste nell'utilizzare un mappatore O/R come SQLObject. Esso eseguirà la maggior parte degli impianti idraulici per mantenere l'oggetto Python in un database e supporta SQLite. Come accennato altrove, è possibile anche serializzare l'oggetto usando un metodo come pickle, che scarica una rappresentazione dell'oggetto che può ricostruire rileggendo e analizzando.

10

Sì, è possibile, ma ci sono diversi approcci e quale è quello adatto, dipenderà dalle vostre esigenze.

  • Decapaggio

    È possibile utilizzare il modulo pickle per serializzare oggetti, quindi memorizzare questi oggetti in un blob in sqlite3 (o una textfield, se la discarica è esempio base64 codificato). Essere a conoscenza di alcuni possibili problemi: questions/198692/can-i-pickle-a-python-dictionary-into-a-sqlite3-text-field

  • Object-Relational Mapping-

    È possibile utilizzare l'oggetto di mapping relazionale. Ciò crea, in effetti, un "database di oggetti virtuali" che può essere utilizzato all'interno del linguaggio di programmazione (Wikipedia). Per Python, c'è un bel toolkit per questo: sqlalchemy.

5

È possibile utilizzare pickle.dumps, il suo ritorno oggetti pickable come stringhe, si avrebbe non c'è bisogno di scriverlo nei file temporanei.

restituire la rappresentazione in salamoia del dell'oggetto come stringa, invece di scriverlo in un file.

import pickle 

class Foo: 
    attr = 'a class attr' 

picklestring = pickle.dumps(Foo) 
0

C'è modo relativamente semplice per memorizzare e confrontare oggetti, eaven all'indice quegli oggetti modo giusto e di limitare (con ubique) colonne contenenti oggetti. E tutto ciò senza utilizzare i motori ORM. Gli oggetti vengono memorizzati usando il pickle pickle (quindi le prestazioni potrebbero essere un problema) Ecco un esempio per la memorizzazione di tuple python, indicizzazione che restringono e confrontano. Questo metodo può essere facilmente applicato a qualsiasi altra classe Python. Tutto ciò che serve è spiegato nella documentazione di python sqlite3 (qualcuno ha già pubblicato il link). Comunque qui è tutto messo insieme nel seguente esempio:

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

A seconda delle vostre esigenze, potrebbe valere la pena guardare in Django (www.djangoproject.com) per questo compito. Django è in realtà un framework web, ma uno dei compiti che gestisce è quello di consentire di definire i modelli come oggetti python (che ereditano da una classe base fornita dal framework). Creerà quindi automaticamente le tabelle del database necessarie per archiviare tali oggetti e sqlite è tra i backend supportati. Fornisce inoltre utili funzioni per interrogare il database e restituire uno o più oggetti corrispondenti. Si veda ad esempio la documentazione sui modelli in django:

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

Lo svantaggio è, naturalmente, che è necessario installare un framework web completo, e (per quanto mi ricordo) si può solo oggetti archivio i cui attributi sono supportato da Django. Inoltre, è fatto per memorizzare molte istanze di oggetti predefiniti, non per memorizzare un'istanza ciascuno di molti oggetti diversi. A seconda delle esigenze, questo può o non può essere poco pratico.

Problemi correlati