SQLAlchemy - 使用主要连接关系加载Eager

时间:2017-12-01 17:31:14

标签: python join sqlalchemy relationship eager-loading

我正在尝试加载一个具有主要条件的关系并且它一直告诉我Unknown column 'tags.type' in 'on clause'。我相信这是因为表名被硬编码到连接中,但查询试图使用表的AS名称。完整示例如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://test:test@localhost/JoinTest'
    db.init_app(app)
    return app

class PostToTags(db.Model):
    __tablename__ ='post_to_tags'
    post_id = db.Column(db.Integer, db.ForeignKey('posts.id'), primary_key=True)
    tag_id = db.Column(db.Integer, db.ForeignKey('tags.id'), primary_key=True)

class Tag(db.Model):
    __tablename__ = 'tags'
    id = db.Column(db.Integer, primary_key=True)
    key = db.Column(db.Unicode(1024), nullable=False)
    value = db.Column(db.Unicode(1024))
    type = db.Column(db.Enum('post'), default=None)

class Post(db.Model):
    __tablename__ = 'posts'

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

    tags = db.relationship(
        "Tag",
        primaryjoin="and_(Post.id == PostToTags.post_id, Tag.type=='post')",
        secondary='post_to_tags',
    )

if __name__ == "__main__":
    app = create_app()
    with app.app_context():
        db.drop_all()
        db.create_all()
        tag = Tag(key='foo',value='bar', type='post')
        post = Post()
        post.tags.append(tag)
        db.session.add_all((post, tag))
        db.session.commit()

        q = db.session.query(Post).options(db.joinedload('tags'))

        print q
        print q.all()

它发出的实际查询如下所示:

SELECT posts.id AS posts_id, tags_1.id AS tags_1_id, tags_1.`key` AS tags_1_key, tags_1.value AS tags_1_value, tags_1.type AS tags_1_type 
FROM posts LEFT OUTER JOIN (post_to_tags AS post_to_tags_1 INNER JOIN tags AS tags_1 ON tags_1.id = post_to_tags_1.tag_id) ON posts.id = post_to_tags_1.post_id AND tags.type = %(type_1)s

请注意,在最后一个ON语句之前,它将tag表命名为tags_1,但是对该表的最后一个引用尝试通过tags.type <访问该属性/ p>

重新考虑这个的最好方法是什么?

提前致谢!

1 个答案:

答案 0 :(得分:0)

你遇到与post you linked几乎相同的问题,但不是简单地从主服务器中删除辅助连接,而是让SQLAlchemy弄明白你需要定义辅助服务而不是主服务器 - 并让SQLA数字主要出自你:

tags = db.relationship(
    "Tag",
    secondaryjoin="and_(Tag.id == PostToTags.tag_id, Tag.type == 'post')",
    secondary='post_to_tags',
)