2009-09-04 6 views
21

Vorrei caricare/salvare un dtt dal/mio DB sqlite, ma sto avendo qualche problema a capire un modo semplice per farlo. Non ho davvero bisogno di essere in grado di filtrare, ecc., In base al contenuto, quindi una semplice conversione da/a una stringa va bene.Dice Python in sqlalchemy

La prossima cosa migliore sarebbero le chiavi esterne. Per favore non postare link a enormi esempi, la mia testa esploderebbe se mai guardassi a quelli.

risposta

4

È possibile creare un tipo personalizzato da sottoclasse sqlalchemy.types.TypeDecorator per gestire la serializzazione e deserializzazione in testo.

Un'implementazione potrebbe essere simile

import json 
import sqlalchemy 
from sqlalchemy.types import TypeDecorator 

SIZE = 256 

class TextPickleType(TypeDecorator): 

    impl = sqlalchemy.Text(SIZE) 

    def process_bind_param(self, value, dialect): 
     if value is not None: 
      value = json.dumps(value) 

     return value 

    def process_result_value(self, value, dialect): 
     if value is not None: 
      value = json.loads(value) 
     return value 

Esempio di utilizzo:

class SomeModel(Base): 
    __tablename__ = 'the_table' 
    id = Column(Integer, primary_key=True) 
    json_field = Column(TextPickleType()) 

s = SomeEntity(json_field={'baked': 'beans', 'spam': 'ham'}) 
session.add(s) 
session.commit() 

Questo è delineato nella an example in the SQLAlchemy docs, che mostra anche come monitorare le mutazioni di quel dizionario.

Questo approccio dovrebbe funzionare per tutte le versioni di Python, mentre semplicemente passando json come valore al pickler argomento PickleType non funziona correttamente, come AlexGrönholm points out nel suo commento su un'altra risposta.

+0

La tua risposta non è completa, quindi non posso accettare. Ha anche riferimenti a "la risposta accettata" che devia qualsiasi tentativo e modifica quello stato particolare in ogni risposta. Per favore, inizia con una risposta corretta e (se devi) includi ciò che altri hanno sbagliato alla fine. –

+0

@ JonasByström abbastanza corretto, ho rimosso il riferimento alla risposta attualmente accettata e esteso l'esempio un po ' – karlson

+0

Questo ha funzionato quando l'ho installato. Comunque dopo aver aggiunto un nuovo campo al mio modello ('product_count = db.Column (db.Integer)') mi dà il seguente errore durante la migrazione delle modifiche a mysql: 'NameError: name 'TextPickleType' non è definito' – iamlolz

3

Se è necessario mappare un 1-N relazione e mappare come dict piuttosto allora list, quindi leggere Dictionary Based Collections

Ma se si intende un campo, allora che cosa si può fare per avere un Campo DB di tipo stringa, che è mappato sul tuo oggetto Python. Ma sullo stesso oggetto python si fornisce una proprietà che sarà il tipo di proxy per questo campo stringa mappato di tipo dict(). Esempio di codice (non testato):

class MyObject(object): 
    # fields (mapped automatically by sqlalchemy using mapper(...) 
    MyFieldAsString = None 

    def _get_MyFieldAsDict(self): 
     if self.MyFieldAsString: 
      return eval(self.MyFieldAsString) 
     else: 
      return {} # be careful with None and empty dict 

    def _set_MyFieldAsDict(self, value): 
     if value: 
      self.MyFieldAsString = str(value) 
     else: 
      self.MyFieldAsString = None 

    MyFieldAsDict = property(_get_MyFieldAsDict, _set_MyFieldAsDict) 
+0

Ahhh! Splendida! :) –

+1

Si noti che SQLAlchemy non vedrà la modifica del contenuto del dict, quindi le modifiche apportate a un dict una volta impostato non verranno mantenute. – Simon

48

Lo SQLAlchemy PickleType è pensato proprio per questo.

class SomeEntity(Base): 
    __tablename__ = 'some_entity' 
    id = Column(Integer, primary_key=True) 
    attributes = Column(PickleType) 

# Just set the attribute to save it 
s = SomeEntity(attributes={'baked': 'beans', 'spam': 'ham'}) 
session.add(s) 
session.commit() 

# If mutable=True on PickleType (the default) SQLAlchemy automatically 
# notices modifications. 
s.attributes['parrot'] = 'dead' 
session.commit() 

È possibile modificare il meccanismo di serializzazione modificando la pickler con qualcos'altro che ha dumps() e loads() metodi. Il meccanismo alla base di stoccaggio da sottoclassi PickleType e override del attritbute impl:

class TextPickleType(PickleType): 
    impl = Text 

import json 
class SomeOtherEntity(Base): 
    __tablename__ = 'some_other_entity' 
    id = Column(Integer, primary_key=True) 
    attributes = Column(TextPickleType(pickler=json)) 
+0

+1: molto bello davvero – van

+0

Bello! Lo proverò per prima cosa lunedì. –

+0

Probabilmente sto facendo qualcosa di gravemente sbagliato quando provo self._properties [k] = v? Ottengo "TypeError: 'Column' object non supporta l'assegnazione dell'oggetto". –