Given the arbitrary example below, I can't ever recall actually using the
FooKeyword association table other than to set up mappings. I came up with
a brute force method to generate the "secondary" table for me
automatically, and I'm hoping someone can show me a better way to do this.
My goal was to take something like this (imports excluded for brevity):
class Keyword(Base):
__tablename__ = 'keyword'
id = Column(Integer, primary_key = True)
name = Column(String, unique = True, nullable = False)
class Foo(Base):
__tablename__ = 'foo'
id = Column(Integer, primary_key = True)
... snip ...
keywords = relationship(Keyword, secondary='foo_keyword')
class FooKeyword(Base):
__tablename__ = 'foo_keyword'
foo_id = Column(Integer, ForeignKey('foo.id'), primary_key = True,
nullable = False)
keyword_id = Column(Integer, ForeignKey('keyword.id'), primary_key
= True, nullable = False)
And replace it with something like this:
class Keyword(Base):
.... snip (same as before) ....
class Foo(Base):
.... snip ....
keywords = generate_many_to_many_for_me('Foo', 'Keyword')
So in the code above, the FooKeyword table would get generated
automatically, and a relationship like "relationship(Keyword,
secondary='foo_keyword') would automatically get returned.
Here is my super naive solution that sort of works:
"""So below here, a call like "secondary_relationship(Foo, Keyword)"
would automatically generate a class called FooKeyword that is
mapped to a table called 'foo_keyword'. It then uses these to return a
relationship equivalent to relationship(Keyword,
secondary='foo_keyword').
You can specify the generated tablename using the tblname arg like so:
"secondary_relationship(Foo, Keyword, "my_tablename")
"""
def secondary_relationship(cls1, cls2, tblname = None):
new_class_name = cls1.__name__ + cls2.__name__
tn1, tn2 = cls1.__tablename__, cls2.__tablename__
tbl = '%s_%s' % (tn1, tn2) if tblname is None else tblname
# Generate the "FooKeyword" table
t = type(new_class_name, (Base,), {
'__tablename__': tbl,
tn1 + '_id': Column(Integer,
ForeignKey('%s.id' % tn1),
primary_key = True, nullable = False),
tn2 + '_id': Column(Integer,
ForeignKey('%s.id' % tn2),
primary_key = True, nullable = False)
})
return relationship(cls2, secondary = tbl)
# the Keyword and Foo classes identical to first example...
class Keyword(Base):
.... snip (same as before) ....
class Foo(Base):
.... snip (same as before except keywords defined below) ....
# And this builds the many to many for us without having to build
FooKeyword class...
Foo.keywords = secondary_relationship(Foo, Keyword)
# You could also do like below to control the tablename generated:
Foo.keywords = secondary_relationship(Foo, Keyword, 'my_tablename')
This actually works, but you can't use this until *after* the definition
for Foo. I'm looking for a way to do this inline in Foo like so:
class Foo(Base):
.... snip ....
keywords = secondary_relationship('Foo', 'Keyword')
Is there a better way? I have spent the better part of the day reading the
source code to see how the declarative extension allows string class names
for relationship, but I still haven't been able to figure this out...
Thanks,
Jeff Peck
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.