SQLAlchemy - 预加载主连接关系
SQLAlchemy - Eager loading with primary join relationship
我正在尝试加载具有 primaryjoin 条件的关系,它一直告诉我 Unknown column 'tags.type' in 'on clause'
。我相信这是因为 table 名称被硬编码到连接中,但查询试图为 table 使用 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
table 命名为 tags_1
,但随后对 table 的最后一个引用试图通过 tags.type
访问属性
重新思考这个问题的最佳方式是什么?
提前致谢!
您遇到的问题与 中的问题几乎相同,但不是简单地从主连接中删除辅助连接并让 SQLAlchemy 计算出来,您需要定义辅助连接而不是主连接 - 让SQLA 为您计算出主要结果:
tags = db.relationship(
"Tag",
secondaryjoin="and_(Tag.id == PostToTags.tag_id, Tag.type == 'post')",
secondary='post_to_tags',
)
我正在尝试加载具有 primaryjoin 条件的关系,它一直告诉我 Unknown column 'tags.type' in 'on clause'
。我相信这是因为 table 名称被硬编码到连接中,但查询试图为 table 使用 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
table 命名为 tags_1
,但随后对 table 的最后一个引用试图通过 tags.type
重新思考这个问题的最佳方式是什么?
提前致谢!
您遇到的问题与
tags = db.relationship(
"Tag",
secondaryjoin="and_(Tag.id == PostToTags.tag_id, Tag.type == 'post')",
secondary='post_to_tags',
)