[sqlalchemy] Mapping not classes but just their keys

2008-06-27 Thread Paul-Michael Agapow


I've got a scenario here that seems as if it would be simple to solve,  
but it baffling me so far. Pointers in the right direction would be  
appreciated.

I have a table of Foo objects, and FooCollection objects. In a classic  
many-to-many, a collection may contain a number of Foos, and any given  
Foo may belong to multiple collections. So far so simple. So we create  
an intermediate table and map accordingly:

 class Foo (object):
 ...

 class FooCollection (object):
 ...

 table_foocollections =  Table ('foocollections', mymetadata, ...)

 table_foo = Table ('foo', mymetadata, ...)

 table_foocollections_foo = Table ('foocollection_foo',
 mymetadata,
 Column ('collection_id',
 None,
 ForeignKey ('foocollections.id'),
 primary_key=True
 ),
 Column ('foo_id',
 None,
 ForeignKey ('foo.id'),
 primary_key=True,
 ),
 )

 mapper (FooCollection, table_foocollections,
 properties={
 'members': relation (FooCollection,
 secondary=table_foocollections_foo,
 ),
 },
 )

So when I retrieve or update a FooCollection, members has all the  
contained Foos.

But, I have a situation where I don't want FooCollection to actually  
contain the actual Foos, just a list of their keys. That is, Foos and  
FooCollections have to be handled separately.  Obviously it will  
involve more paperwork, but how can I make the members attribute  
just contain the keys? Is a mapper extension required, or is there a  
simpler way?

p






--~--~-~--~~~---~--~~
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: Mapping not classes but just their keys

2008-06-27 Thread Paul-Michael Agapow


My, that's fast turnaround :^)

Thanks Michael. If I understand associationproxy right, it requires  
changes to be made to the class, which is a nuisance since one of SA's  
great strengths is that you don't have alter mapped classes. My  
classes are being used in non-DB applications, so I'd prefer to steer  
clear of that. Are there any other possible solutions?

p

On 27 Jun 2008, at 15:57, Michael Bayer wrote:
 On Jun 27, 2008, at 10:12 AM, Paul-Michael Agapow wrote:


 But, I have a situation where I don't want FooCollection to actually
 contain the actual Foos, just a list of their keys. That is, Foos and
 FooCollections have to be handled separately.  Obviously it will
 involve more paperwork, but how can I make the members attribute
 just contain the keys? Is a mapper extension required, or is there a
 simpler way?


 we have a class-level extension called associationproxy thats used
 for this:

 http://www.sqlalchemy.org/docs/05/ 
 plugins.html#plugins_associationproxy

--
Dr Paul-Michael Agapow, VieDigitale / Institute of Animal Health
[EMAIL PROTECTED]


--~--~-~--~~~---~--~~
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] Problems with merge relations

2008-01-30 Thread Paul-Michael Agapow

I'm using merge to push objects into a db. (Long story short: I have  
a set of objects that have to behave identically if they are  
persisted or not, and may be retrieved or sent to a set of databases.  
Hence the use of merge.)  However, merged objects appear object  
joined by a relation and backrefs twice. Is this a bug or an I making  
some subtle mistake?

A condensed demonstration - the names of the mapped objects and  
tables are unimportant, but a Biosequence has a one-to-many with a  
set of Annotations, established by a backref::

from sqlalchemy import *
from sqlalchemy.orm import *

metadata = MetaData()

class Biosequence (object):
pass

class Annotation (object):
pass

table_biosequences = Table ('biosequences', metadata,
Column ('identifier', Integer(), primary_key=True),
Column ('dummy', String(16)),
)

table_seqannotations = Table ('seqannotations', metadata,
Column ('identifier', Integer(), primary_key=True),
Column ('biosequence_id', Integer(), ForeignKey  
('biosequences.identifier')),
)

mapper (Annotation, table_seqannotations)
mapper (Biosequence, table_biosequences,
properties={
'annotations':relation (
Annotation,
backref='biosequence_ref',
lazy=False,
cascade=all, delete, delete-orphan,
),
},
)

engine = create_engine ('sqlite:///', convert_unicode=True,
# echo=True,
)
sessionfactory = sessionmaker (bind=engine, autoflush=False,  
transactional=False)
session = sessionfactory()
metadata.create_all (bind=engine, checkfirst=True)

# make an object with 3 'children'
bseq = Biosequence()
anns = [Annotation() for x in range (3)]
bseq.annotations = anns
print Original num of anns:, len (bseq.annotations)

# the merged copy has 6 children
merge_bseq = session.merge (bseq)
session.flush()
print Now num of anns still:, len (bseq.annotations)
print Ids:, [x.identifier for x in bseq.annotations]
print Merged copy num of anns:, len (merge_bseq.annotations)
print Ids:, [x.identifier for x in merge_bseq.annotations]

# as does the return!
results = session.query (Biosequence)
print Number of results, results.count()
returned_bseq = results.one()
print Returned num of anns:, len (returned_bseq.annotations)
print Ids:, [x.identifier for x in returned_bseq.annotations]

# make an new object with 3 children
bseq2 = Biosequence()
bseq2.annotations = [Annotation() for x in range (3)]
print New obj num of anns:, len (bseq.annotations)
session.save_or_update (bseq2)
session.flush()

# and it works as expected
results = session.query (Biosequence)
print Number of retreived objects, results.count()
returned_bseqs = results.all()
for item in returned_bseqs:
print Returned num of anns:, len (item.annotations)
print Ids:, [x.identifier for x in item.annotations]


Which returns::

Original num of anns: 3
Now num of anns still: 3
Ids: [None, None, None]
Merged copy num of anns: 6
Ids: [1, 1, 2, 2, 3, 3]
Number of results 1
Returned num of anns: 6
Ids: [1, 1, 2, 2, 3, 3]
New obj num of anns: 3
Number of retreived objects 2
Returned num of anns: 6
Ids: [1, 1, 2, 2, 3, 3]
Returned num of anns: 3
Ids: [4, 5, 6]

In summary: if an object is stored using 'save_or_update', when later  
retrieved, it has the correct number of related children. If merged,  
the returned merge copy has each child twice. If this object is  
retrieved later, it still has every child twice.  Looking at the db,  
the correct number of child rows is being stored and the relations  
are correct. It therefore looks like there's a problem in the session  
for merged objects.

Any pointers?

--
Dr Paul-Michael Agapow: VieDigitale / Inst. for Animal Health
[EMAIL PROTECTED] / [EMAIL PROTECTED]




--~--~-~--~~~---~--~~
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] Same schema, multiple databases, simultaneously

2008-01-17 Thread Paul-Michael Agapow


I'm puzzling out how to connect to multiple databases that have the  
same tables (and the same table definitions). The use case is that  
data may be retrieved from two or more similar dbs and perhaps copied  
between them. Following earlier advice, I've used a single metadata  
and 'bind' in the session creation to indicate which engine. However  
there's a problem. Example code below::

from sqlalchemy import *
from sqlalchemy.orm import *

uri1 = # blah blah
uri2 =  # blah blah

class Dummy (object):
simple mapped class
pass

class DbConnection (object):
encapsulate engine  session
def __init__ (self, uri, dbschema):
engine = create_engine (uri)
Session = sessionmaker (bind=engine, autoflush=False,  
transactional=False)
self._session = Session()
dbschema.metadata.create_all (bind=engine, 
checkfirst=True)

def __del__ (self):
self._session.close()


class DbSchema (object):
metadata  table defintions
def __init__ (self):
self.metadata = MetaData()
self.dummy_table = Table('dummy', self.metadata,
Column('id', Integer, primary_key=True),
Column('name', Unicode(40)),
)
mapper (Dummy, self.dummy_table)

# define tables and connect to both dbs
schema = DbSchema()
conn1 = DbConnection (uri1, schema)
conn2 = DbConnection (uri2, schema)

# create object
x = Dummy()
x.name = u'testname'

# save to one and detach object
conn1._session.save_or_update (x)
conn1._session.flush ()
conn1._session.expunge (x)

# save to two silently fails!
conn2._session.save_or_update (x)
conn2._session.flush ()
conn2._session.expunge (x)


The object saves obediently to the first db, but fails to save to the  
second (although tables are created correctly). The successful write  
is always the first one, regardless of the order of opening  
connections. It doesn't depend on how the primary key is defined:  
autogenerated or supplied. I therefore surmise this is because  
'save_or_update' detects the object as already being persistent,  
despite the use of 'expunge'.

Is there another step required to detach the object, or is another  
approach necessary to handle multiple dbs?

--
Dr Paul-Michael Agapow: VieDigitale / Inst. for Animal Health
[EMAIL PROTECTED] / [EMAIL PROTECTED]




--~--~-~--~~~---~--~~
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] Attaching a 'pre-created' class to a session?

2008-01-14 Thread Paul-Michael Agapow

It seems there must be something I'm missing here, so hopefully other  
sets of eyes will spot an obvious mistake.

I have a series of objects that may-or-may not be persistent: some  
will be created and stored to a db, some will be retrieved from the  
db, maybe modified and updated, others will never go anywhere near  
the db. (I have a series of programs using the same objects, only  
some of which need to interact with the db.) However, I'm

A simple test case. Given this code:

class Sample (object):
def __init__ (self, id=None, title=None, description=None):
self.id = id
self.title = title
self.description = description

class Conn (object):
def __init__ (self):
conn_uri = CONN_URI_TMPL % TESTDB_CONNINFO
self.SA_ENGINE = create_engine (conn_uri)
self.SA_METADATA = MetaData (conn_uri)
self.SA_ENGINE.echo = True
Session = sessionmaker (bind=self.SA_ENGINE)
self.SA_SESSION = Session()
self.SA_QUERY = self.SA_SESSION.query

self.SAMPLETABLE = Table ('samples', self.SA_METADATA,
Column ('id', Unicode(32), primary_key=True),
Column ('title', Unicode(32)),
Column ('description', Unicode(32)),
)
self.SA_METADATA.create_all (checkfirst=True)
clear_mappers()
mapper (Sample, self.SAMPLETABLE)

Sample is the class I'd like to be able to persist if needed. Conn  
just encapsulates the connection for test purposes. Now if I do this:

c = Conn()
s1 = Sample()
s1.id = 'foo'
c.SA_SESSION.save_or_update (s1)
c.SA_SESSION.flush()

all is well.  But if I create the Sample before the connection, it  
doesn't work:

s1 = Sample()
s1.id = 'foo'
c = Conn()
c.SA_SESSION.save_or_update (s1)
c.SA_SESSION.flush()


AttributeError: 'ColumnProperty' object has no attribute 'key'

So, how can I persist an object constructed before the connection is  
established? Or is it necessary to do all work either within or  
without of the context of a session?

Thanks

--
Dr Paul-Michael Agapow: VieDigitale / Inst. for Animal Health
[EMAIL PROTECTED] / [EMAIL PROTECTED]




--~--~-~--~~~---~--~~
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: Design: mapped objects everywhere?

2007-12-10 Thread Paul-Michael Agapow

Yowser. Thanks to both of you - that's exactly what I mean. Any  
pointers on where I can find an example of a class that is unaware  
if it is in the db? Or is there a good example of the second  
solution,  of a single class that does the what and why, and an  
interchangeable layer/context that does load/saving? I'm digging  
through dbcook.sf.net but haven't found anything just yet.

On 2007 Dec 7, at 22:07, [EMAIL PROTECTED] wrote:
 Paul Johnston wrote:
 A Sample may be created by the web application or fetched from the
 database. Later on, it may be disposed of, edited or checked back  
 into
 the db.

 Sounds like you want your app to be mostly unaware of whether a  
 class is
 saved in the db or not (i.e. persistent)? If so, I'd use a single  
 class,
 design the properties so they work in non-persistent mode, and then
 they'll work in persistent mode as well.

 or like a single class that does the what and why, and an  
 interchangeable
 layer/context that does load/saving (and the relations!).
 in such situations declarative programming helps a lot, so u dont  
 bind your
 self to (the) db (or whatever persistency). Check dbcook.sf.net. My  
 own
 latest experience is about turning a project that was thought for  
 db/using
 dbcook into non-db simple-file-based persistency. The change was  
 relatively
   small, like 5-10 lines per class - as long as there are  
 Collections etc
 similar notions so Obj side of ORM looks same.



--
Dr Paul-Michael Agapow: VieDigitale / Inst. for Animal Health
[EMAIL PROTECTED] / [EMAIL PROTECTED]




--~--~-~--~~~---~--~~
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] Design: mapped objects everywhere?

2007-12-07 Thread Paul-Michael Agapow

More of a design question, complicated by the fact that I'm a  
database neophyte (although I've used SA a fair bit).

I have a web application that with periodically connect to a  
database. I've written a wrapper for the db using SQLalchemy, but I'm  
unsure about the best way to use the mapped classes. In some cases  
the client will fetch records (mapped classes) from the database and  
immediately use and then dispose of them. No problems. In other  
cases, it will keep those fetched objects around indefinitely,  
perhaps late changing them and sending them back. In even other  
cases, it might create instances of those objects independently of  
the db, and use them, maybe checking them in. Put as a use case:

A Sample may be created by the web application or fetched from the  
database. Later on, it may be disposed of, edited or checked back  
into the db.

So, the design question is should the mapped (database) object  
classes be the same as the extra-db classes? On one hand, it's a lot  
simpler to have a single class Sample, rather than SampleRow (the  
mapped class) and SampleData (an unmapped, extra-db class). On the  
other hand, the requirements and coding of both classes are kinda  
different, and I find myself changing the properties of the mapped  
class for better mapping and making the use of the class in non-Db  
contexts more awkward. Also, the SA magic has made debugging of some  
non-Db issues quite difficult. Opinions or issues to consider.

--
Dr Paul-Michael Agapow: VieDigitale / Inst. for Animal Health
[EMAIL PROTECTED] / [EMAIL PROTECTED]




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