【问题标题】:Error when performing a join in SQLAlchemy 'Please specify the 'onclause' of this join explicitly.'在 SQLAlchemy 中执行连接时出错“请明确指定此连接的 'onclause'。”
【发布时间】:2017-08-20 16:34:21
【问题描述】:

我有以下使用 flask-sqlalchemy 的 sqlalchemy 模型。我的日程表模型中有 3 个 Talentpref 项目。总是需要有 3 个,而且不少于 3 个。

class TalentPref(db.Model):
    __tablename__ = 'talentpref'
    id = db.Column(db.Integer, primary_key=True)
    firstName = db.Column(db.String(80), unique=True)
    lastName = db.Column(db.String(80), unique=True)

    def __init__(self, firstName, lastName):
        self.firstName = firstName
        self.lastName = lastName

    def __repr__(self):
        return '<talentpref %r %r>' % (self.firstName, self.lastName)

class Schedule(db.Model):
    __tablename__ = 'schedule'

    id = db.Column(db.Integer, primary_key=True)

    talentpref1_id = db.Column(db.Integer, db.ForeignKey('talentpref.id'))
    talentpref2_id = db.Column(db.Integer, db.ForeignKey('talentpref.id'))
    talentpref3_id = db.Column(db.Integer, db.ForeignKey('talentpref.id'))

    talentpref1 = db.relationship("TalentPref", uselist=False, foreign_keys=talentpref1_id)
    talentpref2 = db.relationship("TalentPref", uselist=False, foreign_keys=talentpref2_id)
    talentpref3 = db.relationship("TalentPref", uselist=False, foreign_keys=talentpref3_id)

我正在使用 flask-restless 将调度模型作为 api 资源提供服务。当我按计划执行查询并要求按 Talentpref1__lastName 对查询进行排序时,我收到一个错误,该错误与我有多个引用“TalentPref”表的实例有关:

我可以在 id 列上成功使用查询字符串,如下所示:

/api/schedule?id=id&page=1&q={"order_by":[{"field":"id","direction":"desc"}]}

但是使用以下 http GET 查询字符串的查询失败:

/api/schedule?id=id&page=1&q={"order_by":[{"field":"talentpref1__lastName","direction":"desc"}]}

与:

Traceback (most recent call last):
  File "/Users/myuser/Documents/pythonenvironments/venv/lib/python2.7/site-packages/flask_restless/views.py", line 1172, in _search
    result = search(self.session, self.model, search_params)
  File "/Users/myuser/Documents/pythonenvironments/venv/lib/python2.7/site-packages/flask_restless/search.py", line 587, in search
    query = create_query(session, model, search_params, _ignore_order_by)   
  File "/Users/myuser/Documents/pythonenvironments/venv/lib/python2.7/site-packages/flask_restless/search.py", line 549, in create_query
    _ignore_order_by)
  File "/Users/myuser/Documents/pythonenvironments/venv/lib/python2.7/site-packages/flask_restless/search.py", line 498, in create_query
    query = query.join(relation_model)
  File "/Users/myuser/Documents/pythonenvironments/venv/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 1971, in join
    from_joinpoint=from_joinpoint)
  File "<string>", line 2, in _join
  File "/Users/myuser/Documents/pythonenvironments/venv/lib/python2.7/site-packages/sqlalchemy/orm/base.py", line 201, in generate
    fn(self, *args[1:], **kw)
  File "/Users/myuser/Documents/pythonenvironments/venv/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2115, in _join
    outerjoin, full, create_aliases, prop)
  File "/Users/myuser/Documents/pythonenvironments/venv/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2188, in _join_left_to_right
    self._join_to_left(l_info, left, right, onclause, outerjoin, full)   
  File "/Users/myuser/Documents/pythonenvironments/venv/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2317, in _join_to_left
    "Tried joining to %s, but got: %s" % (right, ae))

InvalidRequestError: Could not find a FROM clause to join from.  Tried
joining to <class 'app.model.TalentPref'>, but got: Can't determine
join between 'schedule' and 'talentpref'; tables have more than one
foreign key constraint relationship between them. Please specify the
'onclause' of this join explicitly.

有没有办法可以成功查询到这个关系?

【问题讨论】:

  • 用 http GET 查询字符串更新了帖子
  • 我没有在 Python 中查询。我正在使用flask-restless,它允许您定义一个用作休息资源的模型。您可以使用http参数过滤器查询资源:flask-restless.readthedocs.io/en/stable/…

标签: python sqlalchemy flask-sqlalchemy flask-restless


【解决方案1】:

这似乎是flask-restless 本身的限制。当传递 __ 形式的 时,它将split the name and use the 1st part as the relationship。它使用关系属性来查找要加入的相关模型类:

if '__' in field_name:
    field_name, field_name_in_relation = \
        field_name.split('__')
    relation = getattr(model, field_name)
    relation_model = relation.mapper.class_
    field = getattr(relation_model, field_name_in_relation)
    direction = getattr(field, val.direction)
    query = query.join(relation_model)
    #                  ^^^^^^^^^^^^^^ TalentPref model class
    query = query.order_by(direction())

https://github.com/jfinkels/flask-restless/blob/0.17.0/flask_restless/search.py#L498

在你的情况下这是有效的

query = query.join(TalentPref)

因为你有multiple join paths,SQLAlchemy 无法确定要做什么。如果 flask-restless 要么使用 simple relationship join 而不是加入目标实体,要么将 relationship() 驱动的 ON 子句适应目标实体,这将不是问题。

你可以修补你的flask-restless来修复这个特定的查询:

--- search.py   2017-03-29 09:56:00.439981932 +0300
+++ search_joinfix.py   2017-03-29 09:56:41.375851375 +0300
@@ -495,7 +495,7 @@
                         relation_model = relation.mapper.class_
                         field = getattr(relation_model, field_name_in_relation)
                         direction = getattr(field, val.direction)
-                        query = query.join(relation_model)
+                        query = query.join(relation)
                         query = query.order_by(direction())
                     else:
                         field = getattr(model, val.field)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-29
    • 1970-01-01
    • 2021-11-11
    • 2014-11-26
    • 2018-10-10
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    相关资源
    最近更新 更多