2009-04-23 15 views
15

Ho una domanda riguardante SQLAlchemy. Come posso aggiungere alla mia classe mappata l'attributo simile al dizionario, che mappa le chiavi stringa in valori stringa e che saranno archiviate nel database (nella stessa tabella o in un'altra tabella come oggetto mappato originale). Voglio aggiungere il supporto per tag arbitrari dei miei oggetti.SQLAlchemy - Dizionario di tag

ho trovato il seguente esempio nella documentazione SQLAlchemy:

from sqlalchemy.orm.collections import column_mapped_collection, attribute_mapped_collection, mapped_collection 

mapper(Item, items_table, properties={ 
# key by column 
'notes': relation(Note, collection_class=column_mapped_collection(notes_table.c.keyword)), 
# or named attribute 
'notes2': relation(Note, collection_class=attribute_mapped_collection('keyword')), 
# or any callable 
'notes3': relation(Note, collection_class=mapped_collection(lambda entity: entity.a + entity.b)) 
}) 

item = Item() 
item.notes['color'] = Note('color', 'blue') 

Ma io voglio il seguente comportamento:

mapper(Item, items_table, properties={ 
# key by column 
'notes': relation(...), 
}) 

item = Item() 
item.notes['color'] = 'blue' 

E 'possibile in SQLAlchemy?

Grazie

risposta

21

La risposta semplice è .

Basta usare un proxy associazione:

from sqlalchemy import Column, Integer, String, Table, create_engine 
from sqlalchemy import orm, MetaData, Column, ForeignKey 
from sqlalchemy.orm import relation, mapper, sessionmaker 
from sqlalchemy.orm.collections import column_mapped_collection 
from sqlalchemy.ext.associationproxy import association_proxy 

Creare un ambiente di test:

engine = create_engine('sqlite:///:memory:', echo=True) 
meta = MetaData(bind=engine) 

definire le tabelle:

tb_items = Table('items', meta, 
     Column('id', Integer, primary_key=True), 
     Column('name', String(20)), 
     Column('description', String(100)), 
    ) 
tb_notes = Table('notes', meta, 
     Column('id_item', Integer, ForeignKey('items.id'), primary_key=True), 
     Column('name', String(20), primary_key=True), 
     Column('value', String(100)), 
    ) 
meta.create_all() 

Classes (notare il association_proxy nella classe):

class Note(object): 
    def __init__(self, name, value): 
     self.name = name 
     self.value = value 
class Item(object): 
    def __init__(self, name, description=''): 
     self.name = name 
     self.description = description 
    notes = association_proxy('_notesdict', 'value', creator=Note) 

Mapping:

mapper(Note, tb_notes) 
mapper(Item, tb_items, properties={ 
     '_notesdict': relation(Note, 
      collection_class=column_mapped_collection(tb_notes.c.name)), 
    }) 

Poi basta provarlo:

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

i = Item('ball', 'A round full ball') 
i.notes['color'] = 'orange' 
i.notes['size'] = 'big' 
i.notes['data'] = 'none' 

s.add(i) 
s.commit() 
print i.notes 

che le stampe:

{u'color': u'orange', u'data': u'none', u'size': u'big'} 

Ma, sono quelli della tabella note?

>>> print list(tb_notes.select().execute()) 
[(1, u'color', u'orange'), (1, u'data', u'none'), (1, u'size', u'big')] 

Funziona !! :)

+0

Come si può cancellare 'i' allora?Otterrò un "aise AssertionError" ("La regola delle dipendenze ha cercato di cancellare la colonna della chiave primaria"% s "sull'istanza"% s ""% (r, mapperutil.state_str (dest))) "eccezione quando si prova' s.delete (i) ' – Sardathrion

+0

Rispondendo alla mia domanda:' In mapper (elemento [...], cascade = "all, delete-orphan"), [...] ' – Sardathrion

-6

La semplice risposta è "no".

SQLAlchemy è wrapper su un database SQL.

Gli esempi di relazione citati traducono una relazione tra tabelle SQL in una struttura simile a una mappa Python per semplificare leggermente le istruzioni SQL SELECT e individuare le righe in un'altra tabella.

Il

item.notes['color'] = Note('color', 'blue') 

è essenziale perché la Note è una tabella separata con due colonne. Non è possibile lasciare la parte Note fuori.

È necessario definire questa altra tabella SQL ed è necessario creare oggetti associati a tale tabella SQL.