OK the bad thing is that theres no way ppl are going to be able to  
figure out a relation like this one unless I add crazy amounts of  
docs...anyway, the answer is:

mapper(Section, section_table, properties = {
     'items': relation(Item, backref='section'),
      'keywords':relation(Keyword,
             primaryjoin=and_(
                 keyword_table.c.uuid==itemkeyword_table.c.keyword_uuid,
                 item_table.c.uuid==itemkeyword_table.c.item_uuid,
                 section_table.c.id==item_table.c.section_id),
     viewonly=True, foreign_keys=[keyword_table.c.uuid], remote_side= 
[item_table.c.section_id])
     }
)

the "foreignkey" argument is deprecated, and in the trunk the entire  
system of calculating "what does it mean when we say A relates to B"  
has been highly clarified and strictified, as well as the way it  
calculates the "lazy clause" which is the part that was breaking for  
you.  that logic doesnt find the things it wants to in that big join  
condition you gave it since it cant reconcile "section_table" against  
"keyword_table" in such a way that it also knows where to put the "?"  
for the lazy clause (in previous versions, it made a very good guess,  
which guessed right for things like the above but guessed wrong for a  
lot of other stuff.   now it doesnt guess so much).  of course the  
improvment to make here is to antipicate that particular error and  
raise a nicer message earlier on.

anyway in the above, you give it the foreign key (or however many you  
want to describe) in foreign_keys, and then to tell the lazy loader  
which columns to put the ? in you use remote_side.  the above values  
are a little artificial to make the right thing happen.

alternatively, you can just force your own lazy loader, perhaps I  
should add a recipe for this...its just as functional (except wont  
work for an eager load) and is much more blunt in its intention:

from sqlalchemy.orm.session import attribute_manager
def load_keywords(instance):
     def lazyload():
         session = object_session(instance)
         return session.query(Keyword).select(and_(
             keyword_table.c.uuid==itemkeyword_table.c.keyword_uuid,
             item_table.c.uuid==itemkeyword_table.c.item_uuid,
             instance.id==item_table.c.section_id))
     return lazyload
attribute_manager.register_attribute(Section, 'keywords',  
uselist=True, callable_=load_keywords)

of course thats a variant on whats in the docs, which is just to use  
"property" to make your own function (which IMHO makes the "viewonly"  
flag not really needed).

On Mar 19, 2007, at 9:56 PM, Steve Zatz wrote:

> import uuid as uuid_
> from sqlalchemy import *
>
> def get_uuid():
>     a = str(uuid_.uuid4())
>     a = a.strip('{}')
>     return a.replace('-','')
>
>
> engine = create_engine('sqlite://')
>
> metadata = BoundMetaData(engine)
> engine.echo = True #True
>
>
> item_table = Table('item',metadata,
>               Column('id', Integer, primary_key=True),
>               Column('uuid',String(32), unique=True, nullable=False),
>               Column('parent_uuid', String(32), ForeignKey 
> ('item.uuid'), nullable=True),
>               Column('name',String(150)),
>               Column('section_id', Integer, ForeignKey('section.id'))
> )
>
> section_table = Table('section', metadata,
>                  Column('id', Integer, primary_key=True),
>                  Column('name', String(25), unique=True,  
> nullable=False),
> )
>
> keyword_table = Table('keyword', metadata,
>                  Column('uuid',String(32), primary_key=True),
>                  Column('name', String(25), unique=True,  
> nullable=False)
> )
>
> itemkeyword_table = Table('item_keyword', metadata,
>                       Column('item_uuid', String(32),ForeignKey 
> ('item.uuid'), primary_key=True),
>                       Column('keyword_uuid', String(32), ForeignKey 
> ('keyword.uuid'), primary_key=True),
> )
>
> metadata.create_all()
>
> # class definitions
> class Item(object):
>     def __init__(self, name=None, id=None, uuid=None, **kw):  #?  
> **kw  for x,y in kw, setattr(x) = y
>         self.name = name
>         self.id = id
>         if uuid:
>             self.uuid = uuid
>         else:
>             self.uuid = get_uuid()
>         for k in kw:
>               setattr(self, k, kw[k])
>
>
>     def _get_keywords(self):
>         return [ik.keyword for ik in self.itemkeywords]
>
>     keywords = property(_get_keywords)
>
> class Section(object):
>     def __init__(self, name=None, id=None):
>         self.name = name
>         self.id = id
>
>
> class Keyword(object):
>     def __init__(self, name=None, id=None, uuid=None):
>         self.name = name
>         self.id = id
>         if uuid:
>             self.uuid = uuid
>         else:
>             self.uuid = get_uuid()
>
>
> class ItemKeyword(object):
>     def __init__(self, keyword=None):
>         if keyword:
>             self.keyword = keyword
>
>
> mapper(Section, section_table, properties = {'items': relation 
> (Item, backref='section'), 'keywords':relation(Keyword,
> primaryjoin=and_ 
> (keyword_table.c.uuid==itemkeyword_table.c.keyword_uuid,  
> item_table.c.uuid==itemkeyword_table.c.item_uuid,  
> section_table.c.id==item_table.c.section_id),
> viewonly=True, foreignkey=keyword_table.c.uuid)})
>
> mapper(Keyword, keyword_table)
>
> mapper(Item, item_table, properties = dict(itemkeywords = relation 
> (ItemKeyword, lazy=False, backref='item'),
> children = relation(Item, remote_side=[item_table.c.parent_uuid],  
> backref=backref('parent', remote_side=[item_table.c.uuid])),
> ))
>
> mapper(ItemKeyword, itemkeyword_table, properties={'keyword':  
> relation(Keyword, lazy=False, backref='itemkeywords')})
>
>
> ###################################################################### 
> ###################################################################### 
> ##################
> session = create_session(bind_to=engine)
>
> item1 = Item(name="Item 1")
> section1 = Section(name="Section1")
> keyword1 = Keyword(name="Keyword1")
> session.save(item1)
> session.save(section1)
> session.save(keyword1)
> session.flush()
> item1.itemkeywords.append(ItemKeyword(keyword1))
> session.flush()
> section = session.query(Section).select()[0]
> section.keywords #exception occurs


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to [email protected]
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