SQLAlchemy/Elixir - 查询以检查多对多关系列表中实体的成员资格

发布于 2024-11-15 03:27:14 字数 1324 浏览 2 评论 0原文

我正在尝试构建一个 sqlalchemy 查询来获取 MIT 助理教授的所有教授的姓名列表。请注意,某门课程可以有多名助理教授。

我想做的大致相当于:

uni_mit = University.get_by(name='MIT')
s = select([Professor.name],
           and_(Professor.in_(Course.assistants),
                Course.university = uni_mit))
session.execute(s)

这不起作用,因为 in_ 仅为实体的字段定义,而不是为整个实体定义。无法使用 Professor。 id.in_ as Course.assistants 是教授列表,而不是他们的 id 列表。我也尝试了 contains 但我也没有工作。

我的 Elixir 模型是:

class Course(Entity):
    id = Field(Integer, primary_key=True)
    assistants = ManyToMany('Professor', inverse='courses_assisted', ondelete='cascade')
    university = ManyToOne('University')
    ..

class Professor(Entity):
    id = Field(Integer, primary_key=True)
    name = Field(String(50), required=True)
    courses_assisted = ManyToMany('Course', inverse='assistants', ondelete='cascade')
    ..

如果我可以访问中间多对多实体,这将是微不足道的(条件为 and_(interm_table.prof_id = Professor.id, interm_table.course = Course.id),但 SQLAlchemy 显然对我隐藏了这个表,

我正在使用 Elixir 0.7 和 SQLAlchemy 0.6

顺便说一句:这个问题与 Sqlalchemy+elixir:如何查询多对多关系? 因为我需要检查教授是否满足所有满足条件的课程,而不是单个静态课程。

I am trying to construct a sqlalchemy query to get the list of names of all professors who are assistants professors on MIT. Note that there can be multiple assistant professors associated with a certain course.

What I'm trying to do is roughly equivalent to:

uni_mit = University.get_by(name='MIT')
s = select([Professor.name],
           and_(Professor.in_(Course.assistants),
                Course.university = uni_mit))
session.execute(s)

This won't work, because in_ is only defined for entity's fields, not for the whole entity.. Can't use Professor.id.in_ as Course.assistants is a list of Professors, not a list of their ids. I also tried contains but I didn't work either.

My Elixir model is:

class Course(Entity):
    id = Field(Integer, primary_key=True)
    assistants = ManyToMany('Professor', inverse='courses_assisted', ondelete='cascade')
    university = ManyToOne('University')
    ..

class Professor(Entity):
    id = Field(Integer, primary_key=True)
    name = Field(String(50), required=True)
    courses_assisted = ManyToMany('Course', inverse='assistants', ondelete='cascade')
    ..

This would be trivial if I could access the intermediate many-to-many entity (the condition would be and_(interm_table.prof_id = Professor.id, interm_table.course = Course.id), but SQLAlchemy apparently hides this table from me.

I'm using Elixir 0.7 and SQLAlchemy 0.6.

Btw: This question is different from Sqlalchemy+elixir: How query with a ManyToMany relationship? in that I need to check the professors against all courses which satisfy a condition, not a single, static one.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

妳是的陽光 2024-11-22 03:27:14

您可以找到 Elixir 将其隐藏的中间表,但请注意,它使用完全限定的列名称(例如 __package_path_with_underscores__course_id)。为了避免这种情况,请使用eg定义ManyToMany

class Course(Entity):
    ...
    assistants = ManyToMany('Professor', inverse='courses_assisted',
                            local_colname='course_id', remote_colname='prof_id',
                            ondelete='cascade')

,然后您可以使用访问中间表

rel = Course._descriptor.find_relationship('assistants')
assert rel
table = rel.table

,并可以使用table.c.prof_id等访问列。

更新:当然您可以在更高级别执行此操作,但不能在单个查询中执行此操作,因为 SQLAlchemy 尚不支持关系的 in_ 。例如,对于两个查询:

>>> mit_courses = set(Course.query.join(
... University).filter(University.name == 'MIT'))
>>> [p.name for p in Professor.query if set(
... p.courses_assisted).intersection(mit_courses)]

或者,或者:

>>> plist = [c.assistants for c in Course.query.join(
... University).filter(University.name == 'MIT')]
>>> [p.name for p in set(itertools.chain(*plist))]

第一步创建助理列表的列表。第二步压平列表列表并通过创建集合来删除重复项。

You can find the intermediate table where Elixir has hidden it away, but note that it uses fully qualified column names (such as __package_path_with_underscores__course_id). To avoid this, define your ManyToMany using e.g.

class Course(Entity):
    ...
    assistants = ManyToMany('Professor', inverse='courses_assisted',
                            local_colname='course_id', remote_colname='prof_id',
                            ondelete='cascade')

and then you can access the intermediate table using

rel = Course._descriptor.find_relationship('assistants')
assert rel
table = rel.table

and can access the columns using table.c.prof_id, etc.

Update: Of course you can do this at a higher level, but not in a single query, because SQLAlchemy doesn't yet support in_ for relationships. For example, with two queries:

>>> mit_courses = set(Course.query.join(
... University).filter(University.name == 'MIT'))
>>> [p.name for p in Professor.query if set(
... p.courses_assisted).intersection(mit_courses)]

Or, alternatively:

>>> plist = [c.assistants for c in Course.query.join(
... University).filter(University.name == 'MIT')]
>>> [p.name for p in set(itertools.chain(*plist))]

The first step creates a list of lists of assistants. The second step flattens the list of lists and removes duplicates through making a set.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文