SQLAlchemy与联接,我们没有外键

8 投票
1 回答
11991 浏览
提问于 2025-04-16 19:35

假设在MySQL中有以下内容:

CREATE TABLE users (
  id integer auto_increment primary key,
  username varchar(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
);

注意,这些表没有添加正式的外键约束。这是我接手的项目,当前的设置我无法更改。(我们正在全面改造整个系统,但在此期间我必须使用现有的设置)

我在理解SQLalchemy的连接操作时遇到了困难,因为表之间没有正式的外键。

实际上,我想做的事情是:

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;

我写的代码包括以下内容:

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

... 当然,这样会失败,错误信息是:

sqlalchemy.exc.ArgumentError: Can't find any foreign key relationships
between 'users' and 'comments'.

当没有外键时,我不确定该如何解决这个问题。我该如何定义表之间的关系呢?我以为这应该在mapper()调用中处理:

mapper(UserComments, j, properties={'user_id': [users.c.id, 
    comments.c.user_id]})

... 但显然我误解了文档的意思。

提前感谢任何帮助。

1 个回答

25

你有两个选择。你可以像这样在 join 中传入连接条件:

j = join(users, comments, onclause=users.c.id == commends.c.user_id)

如果你是在定义一个 orm.relationship 属性,那么关键字参数应该用 primaryjoin,而不是 onclause

不过,我更喜欢的做法是直接 撒谎。告诉 SQLAlchemy 有一个外键,尽管实际上并没有。

comments = Table('comments', metadata,
    Column('id', Integer, primary_key=True),
    Column('user_id', Integer, ForeignKey('users.id')),
    ...
)

SQLAlchemy 会假装这个外键确实存在,尽管实际的数据库里没有。当然,如果这个隐含的外键约束被违反了(比如 comments.user_id 没有对应的 users.id),你可能会遇到麻烦,但反正你可能已经有麻烦了。

撰写回答