maybe try, instead of hiding the conversion inside db-types layer, to 
move it upper, i.e. make it a real reference/FK-column to real 
object/table, then make a python property (see "synonim") to do the 
conversion.

On Tuesday 30 September 2008 23:20:16 rca wrote:
> Hi all,
>
> my apologies for a long question, I am new to sqlalchemy and I was
> struggling with one problem. I solved it but I really not sure it's
> the right way to do it.
>
> The problem is that I need to create objects like this:
> Token(pos=2, surface="helloWorld")
>
> The surface is string, but in the database, it should be saved as
> reference to an other table (looked-up and saved if not existing)
>
>
> The way I solved it was to create my own column type decorating
> Integer. On the way in, it gets text and stores id, on the way out,
> it gives the text back.
>
> But I don't know if my solution is safe. For instance,
> -- I am decorating Integer type, but on the output there is string.
> -- I am using the EntitySingleton recipy, but I found out I could
> not use the recommended
> Session = scoped_session(sessionmaker())
> I had to say: Session = sessionmaker()
> -- And I do commit for every new looked-up value
>
> And also, I have the impression the solution is very complicated,
> perhaps you could help me to do it in a better way.
>
> Many thanks!
>
>   roman
>
> Here is the code with an example:
> -------------------------------------------------------
>
> import sqlalchemy as sa
> from sqlalchemy.ext.declarative import declarative_base
> from sqlalchemy.orm import scoped_session, sessionmaker, relation,
> backref, mapper
> from sqlalchemy import create_engine, Table, Column, Integer,
> String, MetaData, ForeignKey
> #from mimetypes import types_map
> import weakref
> import sqlalchemy.types as types
>
>
> Session = sessionmaker()  #scoped_session(sessionmaker)
>
> DBase = declarative_base()
>
> class MyUnique(types.TypeDecorator):
>     """a type that decorates Integer,
>     receives a text representation - eg. MyValueFromEnumeration
>     and replaces it in the database with id of the string above
>     It makes sure that inserted values are unique (creates them if
> not exist)"""
>
>     impl = types.Integer
>
>     def process_bind_param(self, value, dialect):
>         #ukladani do databaze
>         if not hasattr(self, '__unique_valuee'):
>             self.__unique_valuee = Surface(value)
>         return self.__unique_valuee.id
>
>     def process_result_value(self, value, dialect):
>         #vystup
>         return self.__unique_valuee.surface
>
>     """ #if it is string type
>     def copy(self):
>         return MyUniqueString(self.impl.length)
>     """
>
> class DocumentBase(object):
>     def __init__(self):
>         self.metadata = DBase.metadata
>         self.engine = None
>
>     def open(self, url='sqlite:///:memory:'):
>         self.engine = create_engine(url, echo=True)
>         #engine = create_engine('sqlite:///' + __file__ + ".db",
> echo=True)
>         Session.configure(bind=self.engine)
>         self.metadata.bind = self.engine
>
>
>         surface_table = sa.Table('surface', self.metadata,
>             sa.Column('id', sa.Integer, primary_key=True,
> autoincrement=True),
>             sa.Column('surface', sa.String(500),
> autoincrement=True) )
>
>         mapper(Surface, surface_table)
>
>         self.metadata.create_all(checkfirst=True)
>
>     def add(self, document_object):
>         sess = Session()
>         sess.save_or_update(document_object)
>         sess.commit()
>
>
>
> class EntitySingleton(type):
>     """a metaclass that insures the creation of unique and non-
> existent entities for
>     a particular constructor argument.  if an entity with a
> particular constructor
>     argument was already created, either in memory or in the
> database, it is returned
>     in place of constructing the new instance."""
>
>     def __init__(cls, surface, bases, dct):
>         cls.instances = weakref.WeakValueDictionary()
>
>     def __call__(cls, surface):
>         session = Session()
>
>         hashkey = surface
>         try:
>             return cls.instances[hashkey]
>         except KeyError:
>             instance =
> session.query(cls).filter(cls.surface==surface).first()
>             if instance is None:
>                 instance = type.__call__(cls, surface)
>                 #session.begin_nested()
>                 session.add(instance)
>                 session.commit()
>                 # optional - flush the instance when it's saved
>                 session.flush([instance])
>             cls.instances[hashkey] = instance
>             return instance
>
> class Document(DBase):
>     __tablename__ = 'documents'
>     id = sa.Column(sa.Integer(9), primary_key=True,
> autoincrement=True)
>     name = sa.Column(sa.String(500))
>     uri = sa.Column(sa.String(500))
>     processing_stage = sa.Column(sa.String(500))
>
>     tokens = relation("Token", backref="Document")
>
>     def __xinit__(self, name):
>         self.name = name
>     def __repr__(self):
>         return "<%s('%s','%s')>" % (self.__class__, self.id,
> self.name)
>
> class Token(DBase):
>     __tablename__ = 'tokens'
>     id = sa.Column(sa.Integer(6), primary_key=True,
> autoincrement=True)
>     pos = sa.Column(sa.Integer(6))
>     type = sa.Column(sa.String(500))
>     surface = sa.Column(MyUnique(500), sa.ForeignKey('surface.id'))
>     surface_translated = sa.Column(sa.String(500))
>     sem = sa.Column(sa.String(500))
>
>     title_id = sa.Column(sa.Integer, sa.ForeignKey('documents.id'))
>     #document = relation("Document", backref="Token")
>
>     #def __init__(self, surface=None, **kwargs):
>
>
>     def __repr__(self):
>         return "<%s('%s','%s')>" % (self.__class__, self.id,
> self.surface)
>
>
> class Surface(object):
>     __metaclass__ = EntitySingleton
>     #__tablename__ = 'surface'
>     #id = sa.Column(sa.Integer(6), primary_key=True,
> autoincrement=True)
>     #surface = sa.Column(sa.String(500), primary_key=True)
>     def __init__(self, value):
>         self.surface = value
>
>
>
>
>
> def test_database():
>     session = Session()
>     doc = Document(uri="xx1", name="TestDoc")
>     doc.name = "Test"
>     for i in range(1,5):
>         t = Token(pos=i, surface="Text" + str(i))
>         doc.tokens.append(t)
>     #insert the same values again
>     for i in range(1,5):
>         t = Token(pos=i, surface="Text" + str(i))
>         doc.tokens.append(t)
>     session.add(doc)
>     session.commit()
>     print doc.tokens
>     print
>
> if __name__ == "__main__":
>     db = DocumentBase()
>     db.open()
>     test_database()
>
> 


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to