SQLAlchemy and joins, we have no foreign keys
Assume the following in MySQL:
CREATE TABLE users (
id integer auto_increment primary key,
username varc开发者_开发技巧har(30),
active enum('N','Y'),
created_on int(11),
updated_on int(11),
points int(10),
// other fields
);
CREATE TABLE comments (
id integer auto_increment primary key,
user_id integer,
forum_id integer,
favorited integer,
// other fields
);
Note that no formal foreign key constraints are added to the tables. This is something I've inherited and cannot change on our current setup. (We're overhauling the whole system, but in the meantime I have to work with what I've been given)
I'm having trouble wrapping my head around SQLalchemy's joins when there's no formal foreign key established between tables.
Effectively, I'd like to do something like:
SELECT
u.username,
c.forum_id,
count(c.id)
FROM
users u
JOIN comments c ON u.id=c.user_id
WHERE
u.id = 1234
GROUP BY
u.username,
c.forum_id;
Code I have includes things like the following:
mapper(Users, users, primary_key=[users.c.id],
include_properties=['user_id', 'username', 'active', 'created_on',
'updated_on', 'points'])
mapper(Comments, comments, primary_key=[comments.c.id],
include_properties=['active', 'user_id', 'favorited', 'forum_id'])
j = join(users, comments)
mapper(UserComments, j, properties={'user_id': [users.c.id,
comments.c.user_id]})
session = create_session()
query = session.query(UserComments).filter(users.cid == 1234)
rdata = run(query)
for row in rdata:
print row
... which of course fails with:
sqlalchemy.exc.ArgumentError: Can't find any foreign key relationships
between 'users' and 'comments'.
I'm not sure how to work around this when we have no foreign keys. How else do I define the relationship? I thought it was part of the mapper() call:
mapper(UserComments, j, properties={'user_id': [users.c.id,
comments.c.user_id]})
... but apparently I've misread the documentation.
Thanks in advance for any help.
You have two options. You can pass the join condition in join
like so:
j = join(users, comments, onclause=users.c.id == commends.c.user_id)
If you're defining this in terms of a orm.relationship
property, the keyword parameter will be primaryjoin
instead of onclause
.
However, the approach I Prefer is to just lie. Inform SQLAlchemy that there is a foreign key, even though there is not.
comments = Table('comments', metadata,
Column('id', Integer, primary_key=True),
Column('user_id', Integer, ForeignKey('users.id')),
...
)
SQLAlchemy will the proceed as if the foreign key were in fact present, even though the actual database doesn't have that. Of course, you may run into trouble if the implied foriegn key constraint is violated (comments.user_id
when there's no corresponding users.id
), but you'd probably be in trouble anyway.
精彩评论