[sqlalchemy] Re: enumeration values in the column - referenced from another table

2008-10-04 Thread az

 one question to sqlalchemy experts: is it possible to reduce the
 number of queries? i noticed that objects are reloaded every time
 insert/update is done even though in many cases the session already
 contains the data (and it would be ok just to check that
 insert/update operations on the db level succeeded)...
see arguments to sessioncreator, different flavours (e.g. 
create_session vs sessionmaker) have diff. defaults, pick a subset 
that suits u.


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



[sqlalchemy] Re: enumeration values in the column - referenced from another table

2008-10-03 Thread rca

i cant attach the file, so posting here at least as a reference.- i
finally solved the whole problem and i also believe it is not
overcomplicated. basically, i needed to have a composite object,
access its attributes (which are another objects), and to keep the
interface very simple to be able to send a simple str values. The
values must be checked/converted (in my case, they must be unique, and
created if not present). the solution is a combination of
EntitySingleton example, association proxy, and some aching back

one question to sqlalchemy experts: is it possible to reduce the
number of queries? i noticed that objects are reloaded every time
insert/update is done even though in many cases the session already
contains the data (and it would be ok just to check that insert/update
operations on the db level succeeded)...

from sqlalchemy import *
from sqlalchemy.orm import mapper, sessionmaker, relation, backref,
scoped_session
from sqlalchemy.ext.associationproxy import association_proxy
import weakref
import operator
import sys
from sqlalchemy.ext.associationproxy import AssociationProxy


Session = sessionmaker()


#engine = create_engine('sqlite:///:memory:', echo=True)
engine = create_engine('sqlite:///test.sqlite', echo=True)
metadata = MetaData(engine)


document_table = Table('document_table', metadata,
Column('id', Integer(9), primary_key=True, autoincrement=True),
Column('name', String(500)),
Column('uri', String(500)),
Column('processing_stage', String(500)),
)
token_table = Table('token_table', metadata,
Column('id', Integer(9), primary_key=True, autoincrement=True),
Column('document_id', Integer, ForeignKey('document_table.id')),
Column('pos', Integer(6)),
Column('type', String(255)), #pozdeji to udelame sequence
Column('surface_id', Integer, ForeignKey('surface_table.id')),
Column('stripped_surface_id', Integer,
ForeignKey('stripped_surface_table.id')),
Column('sem_id', Integer, ForeignKey('sem_table.id')),
)
surface_table = Table('surface_table', metadata,
Column('id', Integer, primary_key=True, autoincrement=True),
Column('value', String(500))
)
stripped_surface_table = Table('stripped_surface_table', metadata,
Column('id', Integer, primary_key=True, autoincrement=True),
Column('value', String(500))
)
sem_table = Table('sem_table', metadata,
Column('id', Integer, primary_key=True, autoincrement=True),
Column('value', String(500))
)


def myassociation_proxy(target_collection, attr, **kw):
return MyAssociationProxy(target_collection, attr, **kw)

class MyAssociationProxy(AssociationProxy):

I need to change the behaviour of the AssociationProxy - to force
it not to update
attributes when they are replaced. Ie. obj.tokens = 'XXX' will
keep the old token
unchanged.
I tried with getset_factory, but the problem is i cant replace the
instance
from the setter (or at least i dont know how to replace the
self.target_collection
with a new instance)
The behaviour is changed only for scalars, for lists it remains
the same as before

def __set__(self, obj, values):
if self.owning_class is None:
self.owning_class = type(obj)
if self.scalar is None:
self.scalar = self._target_is_scalar()
if self.scalar:
self._initialize_scalar_accessors()

if self.scalar:
creator = self.creator and self.creator or
self.target_class
target = getattr(obj, self.target_collection)
#make sure we add only the different instnces
new_object = creator(values)
if new_object is not getattr(obj, self.target_collection):
setattr(obj, self.target_collection, new_object)
#setattr(obj, self.target_collection, creator(values))

else:
proxy = self.__get__(obj, None)
if proxy is not values:
proxy.clear()
self._set(proxy, values)



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, value):
session = Session()
target_attribute = getattr(cls, getattr(cls,
'target_attribute'))
hashkey = value
try:
return cls.instances[hashkey]
except KeyError:
instance =
session.query(cls).filter(target_attribute==value).first()
if instance is None:
instance = type.__call__(cls, value)
# optional - flush the instance when it's saved
# session.flush([instance])

[sqlalchemy] Re: enumeration values in the column - referenced from another table

2008-10-02 Thread rca

thanks for the pointer, I tried and finally managed something the
synonym (with the big neon don't panic in my head)

I can do the conversion and insert integers id in place of textual
representation and when accessing the parameter .surface, get the
textual representation instead of id
In this way, it works the same as my own type, but just more flexible
(it can access other parameters of the object).

But still... is there a way to map one class to two tables in one go?

To have :
  obj.surface_id -- table1.surface_id
  obj.surface -- table2.surface

when you do:
  obj.surface = XXX
  obj.name=YYY
to have sqlachemy do:
  UPDATE table2 SET surface='XXX' WHERE table2.id = 2 (this is a
foreign key, the value is in the table1.surface_id)
*AND*
  UPDATE table1 SET name='YYY' WHERE table1.id = 8

i am getting this, which is wrong, because surface is foreign key, an
integer:
SELECT s1.* FROM table1 AS s1 WHERE s2.surface_id = 'XXX'

if using the custom type, i am able to translate the attribute to its
id, and use it in the query, yet the synonym might be better, only if
it was possible to do
session.query(Object).filter(Object.surface== XXX)
and get: SELECT s1.*, s2.* FROM table1 AS s1 LEFT JOIN table2 AS s2 ON
s1.surface_id = s2.id WHERE s2.surface = 'XXX'


remember, my goal was to use obj.surface = XXX and have this value
referenced from the other table.

Sorry if my questions are stupid!

--roman

On Oct 1, 10:21 am, [EMAIL PROTECTED] wrote:
 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 

[sqlalchemy] Re: enumeration values in the column - referenced from another table

2008-10-02 Thread az

if the tables have nothing in common, u can have a MapperExtension 
that when touching one item updates the proper table.
as a working big example, 
see sqlalachemyAggregator, either in http://dev.gafol.net/t/aggregator 
or 
http://dbcook.svn.sourceforge.net/viewvc/dbcook/trunk/dbcook/misc/aggregator/
which does things like counting summing etc 
runtime-updates-of-some-cache.
but i'm not sure if that is what u want; imo u need it more explicit 
than this..

and i still cant see how obj.surface=xyz will lookup and populate 
surface_id. imo u need 3 attributes:
 - _surface_text - table1.surface, hidden
 - _surface_id  - table2.surface, hidden
 - surface: property which is visible and does the dispatch/lookup etc

ciao

On Thursday 02 October 2008 13:59:40 rca wrote:
 thanks for the pointer, I tried and finally managed something the
 synonym (with the big neon don't panic in my head)

 I can do the conversion and insert integers id in place of
 textual representation and when accessing the parameter .surface,
 get the textual representation instead of id
 In this way, it works the same as my own type, but just more
 flexible (it can access other parameters of the object).

 But still... is there a way to map one class to two tables in one
 go?

 To have :
   obj.surface_id -- table1.surface_id
   obj.surface -- table2.surface

 when you do:
   obj.surface = XXX
   obj.name=YYY
 to have sqlachemy do:
   UPDATE table2 SET surface='XXX' WHERE table2.id = 2 (this is a
 foreign key, the value is in the table1.surface_id)
 *AND*
   UPDATE table1 SET name='YYY' WHERE table1.id = 8

 i am getting this, which is wrong, because surface is foreign key,
 an integer:
 SELECT s1.* FROM table1 AS s1 WHERE s2.surface_id = 'XXX'

 if using the custom type, i am able to translate the attribute to
 its id, and use it in the query, yet the synonym might be better,
 only if it was possible to do
 session.query(Object).filter(Object.surface== XXX)
 and get: SELECT s1.*, s2.* FROM table1 AS s1 LEFT JOIN table2 AS s2
 ON s1.surface_id = s2.id WHERE s2.surface = 'XXX'


 remember, my goal was to use obj.surface = XXX and have this
 value referenced from the other table.

 Sorry if my questions are stupid!

 --roman

 On Oct 1, 10:21 am, [EMAIL PROTECTED] wrote:
  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 

[sqlalchemy] Re: enumeration values in the column - referenced from another table

2008-10-02 Thread rca

Thanks again, it is much appreciated


On Oct 2, 1:03 pm, [EMAIL PROTECTED] wrote:
 if the tables have nothing in common, u can have a MapperExtension
 that when touching one item updates the proper table.
 as a working big example,
 see sqlalachemyAggregator, either inhttp://dev.gafol.net/t/aggregator
 orhttp://dbcook.svn.sourceforge.net/viewvc/dbcook/trunk/dbcook/misc/agg...
 which does things like counting summing etc
 runtime-updates-of-some-cache.
 but i'm not sure if that is what u want; imo u need it more explicit
 than this..

I have the same feeling (much less assertive here, me, the sql/alchemy
noop)
but i will study the example


 and i still cant see how obj.surface=xyz will lookup and populate
 surface_id. imo u need 3 attributes:
  - _surface_text - table1.surface, hidden
  - _surface_id  - table2.surface, hidden
  - surface: property which is visible and does the dispatch/lookup etc

yes, the three attributes, i am able to do this now - what I am unable
is to map them to different tables -- and be persisted when
session.save(obj) -- and
session.query(obj).filter(obj.attribute_from_the_second_table)
It must be something stupid, i will try to come with an example



 ciao

 On Thursday 02 October 2008 13:59:40 rca wrote:

  thanks for the pointer, I tried and finally managed something the
  synonym (with the big neon don't panic in my head)

  I can do the conversion and insert integers id in place of
  textual representation and when accessing the parameter .surface,
  get the textual representation instead of id
  In this way, it works the same as my own type, but just more
  flexible (it can access other parameters of the object).

  But still... is there a way to map one class to two tables in one
  go?

  To have :
    obj.surface_id -- table1.surface_id
    obj.surface -- table2.surface

  when you do:
    obj.surface = XXX
    obj.name=YYY
  to have sqlachemy do:
    UPDATE table2 SET surface='XXX' WHERE table2.id = 2 (this is a
  foreign key, the value is in the table1.surface_id)
  *AND*
    UPDATE table1 SET name='YYY' WHERE table1.id = 8

  i am getting this, which is wrong, because surface is foreign key,
  an integer:
  SELECT s1.* FROM table1 AS s1 WHERE s2.surface_id = 'XXX'

  if using the custom type, i am able to translate the attribute to
  its id, and use it in the query, yet the synonym might be better,
  only if it was possible to do
  session.query(Object).filter(Object.surface== XXX)
  and get: SELECT s1.*, s2.* FROM table1 AS s1 LEFT JOIN table2 AS s2
  ON s1.surface_id = s2.id WHERE s2.surface = 'XXX'

  remember, my goal was to use obj.surface = XXX and have this
  value referenced from the other table.

  Sorry if my questions are stupid!

  --roman

  On Oct 1, 10:21 am, [EMAIL PROTECTED] wrote:
   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 

[sqlalchemy] Re: enumeration values in the column - referenced from another table

2008-10-02 Thread rca

i think this should be it:
http://www.sqlalchemy.org/docs/04/plugins.html#plugins_associationproxy

and relevant discussion here:
http://groups.google.com/group/sqlalchemy/browse_thread/thread/52565295f54fd85/31f53dca1e31e5ee?hl=enlnk=gstq=mapper+for+two+tables#31f53dca1e31e5ee


On Oct 2, 3:50 pm, rca [EMAIL PROTECTED] wrote:
 Thanks again, it is much appreciated

 On Oct 2, 1:03 pm, [EMAIL PROTECTED] wrote:

  if the tables have nothing in common, u can have a MapperExtension
  that when touching one item updates the proper table.
  as a working big example,
  see sqlalachemyAggregator, either inhttp://dev.gafol.net/t/aggregator
  orhttp://dbcook.svn.sourceforge.net/viewvc/dbcook/trunk/dbcook/misc/agg...
  which does things like counting summing etc
  runtime-updates-of-some-cache.
  but i'm not sure if that is what u want; imo u need it more explicit
  than this..

 I have the same feeling (much less assertive here, me, the sql/alchemy
 noop)
 but i will study the example



  and i still cant see how obj.surface=xyz will lookup and populate
  surface_id. imo u need 3 attributes:
   - _surface_text - table1.surface, hidden
   - _surface_id  - table2.surface, hidden
   - surface: property which is visible and does the dispatch/lookup etc

 yes, the three attributes, i am able to do this now - what I am unable
 is to map them to different tables -- and be persisted when
 session.save(obj) -- and
 session.query(obj).filter(obj.attribute_from_the_second_table)
 It must be something stupid, i will try to come with an example



  ciao

  On Thursday 02 October 2008 13:59:40 rca wrote:

   thanks for the pointer, I tried and finally managed something the
   synonym (with the big neon don't panic in my head)

   I can do the conversion and insert integers id in place of
   textual representation and when accessing the parameter .surface,
   get the textual representation instead of id
   In this way, it works the same as my own type, but just more
   flexible (it can access other parameters of the object).

   But still... is there a way to map one class to two tables in one
   go?

   To have :
     obj.surface_id -- table1.surface_id
     obj.surface -- table2.surface

   when you do:
     obj.surface = XXX
     obj.name=YYY
   to have sqlachemy do:
     UPDATE table2 SET surface='XXX' WHERE table2.id = 2 (this is a
   foreign key, the value is in the table1.surface_id)
   *AND*
     UPDATE table1 SET name='YYY' WHERE table1.id = 8

   i am getting this, which is wrong, because surface is foreign key,
   an integer:
   SELECT s1.* FROM table1 AS s1 WHERE s2.surface_id = 'XXX'

   if using the custom type, i am able to translate the attribute to
   its id, and use it in the query, yet the synonym might be better,
   only if it was possible to do
   session.query(Object).filter(Object.surface== XXX)
   and get: SELECT s1.*, s2.* FROM table1 AS s1 LEFT JOIN table2 AS s2
   ON s1.surface_id = s2.id WHERE s2.surface = 'XXX'

   remember, my goal was to use obj.surface = XXX and have this
   value referenced from the other table.

   Sorry if my questions are stupid!

   --roman

   On Oct 1, 10:21 am, [EMAIL PROTECTED] wrote:
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
 

[sqlalchemy] Re: enumeration values in the column - referenced from another table

2008-10-02 Thread az

On Thursday 02 October 2008 17:13:24 rca wrote:
 i think this should be it:
 http://www.sqlalchemy.org/docs/04/plugins.html#plugins_associationp
roxy

 and relevant discussion here:
 http://groups.google.com/group/sqlalchemy/browse_thread/thread/5256
5295f54fd85/31f53dca1e31e5ee?hl=enlnk=gstq=mapper+for+two+tables#3
1f53dca1e31e5ee

 On Oct 2, 3:50 pm, rca [EMAIL PROTECTED] wrote:
  Thanks again, it is much appreciated
 
  On Oct 2, 1:03 pm, [EMAIL PROTECTED] wrote:
   if the tables have nothing in common, u can have a
   MapperExtension that when touching one item updates the proper
   table.
   as a working big example,
   see sqlalachemyAggregator, either
   inhttp://dev.gafol.net/t/aggregator
   orhttp://dbcook.svn.sourceforge.net/viewvc/dbcook/trunk/dbcook/
  misc/agg... which does things like counting summing etc
   runtime-updates-of-some-cache.
   but i'm not sure if that is what u want; imo u need it more
   explicit than this..
 
  I have the same feeling (much less assertive here, me, the
  sql/alchemy noop)
  but i will study the example
 
   and i still cant see how obj.surface=xyz will lookup and
   populate surface_id. imo u need 3 attributes:
    - _surface_text - table1.surface, hidden
    - _surface_id  - table2.surface, hidden
    - surface: property which is visible and does the
   dispatch/lookup etc
 
  yes, the three attributes, i am able to do this now - what I am
  unable is to map them to different tables -- and be persisted
  when session.save(obj) -- and
  session.query(obj).filter(obj.attribute_from_the_second_table)
  It must be something stupid, i will try to come with an example

hhmm depends if these 2 separate tables are also your objects or just 
lookup tables. if they are objetcs, then _surf1 shoud point to that 
Obj1/table1 object and change the attribute there; same for _surf2 / 
Obj2/table2.

if they're just lookup tables, then i dont know. how u link to which 
record to update? give example.

   ciao
  
   On Thursday 02 October 2008 13:59:40 rca wrote:
thanks for the pointer, I tried and finally managed something
the synonym (with the big neon don't panic in my head)
   
I can do the conversion and insert integers id in place of
textual representation and when accessing the parameter
.surface, get the textual representation instead of id
In this way, it works the same as my own type, but just more
flexible (it can access other parameters of the object).
   
But still... is there a way to map one class to two tables in
one go?
   
To have :
  obj.surface_id -- table1.surface_id
  obj.surface -- table2.surface
   
when you do:
  obj.surface = XXX
  obj.name=YYY
to have sqlachemy do:
  UPDATE table2 SET surface='XXX' WHERE table2.id = 2 (this
is a foreign key, the value is in the table1.surface_id)
*AND*
  UPDATE table1 SET name='YYY' WHERE table1.id = 8
   
i am getting this, which is wrong, because surface is foreign
key, an integer:
SELECT s1.* FROM table1 AS s1 WHERE s2.surface_id = 'XXX'
   
if using the custom type, i am able to translate the
attribute to its id, and use it in the query, yet the synonym
might be better, only if it was possible to do
session.query(Object).filter(Object.surface== XXX)
and get: SELECT s1.*, s2.* FROM table1 AS s1 LEFT JOIN table2
AS s2 ON s1.surface_id = s2.id WHERE s2.surface = 'XXX'
   
remember, my goal was to use obj.surface = XXX and have
this value referenced from the other table.
   
Sorry if my questions are stupid!
   
--roman
   
On Oct 1, 10:21 am, [EMAIL PROTECTED] wrote:
 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 

[sqlalchemy] Re: enumeration values in the column - referenced from another table

2008-10-01 Thread az

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