连接上的 Flask-sqlalchemy ORM TypeError
Flask-sqlalchemy ORM TypeError on a join
我在将有效的 SQL 文本转换为 ORM 命令时遇到问题...
select ctx_j.name as cat_name, x.id as value_id, x.value_r1 as r1,
x.value_r2 as r2, x.value_r3 as r3, x.value_r4 as r4
from (
select cv.id as id, cs.name as name
from context_values cv
left join context_categories cs
on cv.cat_id=cs.id
where cv.verified is True
) as ctx_j
left join (
select t3.id as id, value_r1, value_r2, value_r3, value_r4
from (((((
context_values as v
left join context_value_r1 as r1 on v.id=r1.value_id) as t1
left join context_value_r2 as r2 on t1.id=r2.value_id) as t2
left join context_value_r3 as r3 on t2.id=r3.value_id) as t3
left join context_value_r4 as r4 on t3.id=r4.value_id
) as x on ctx_j.id=x.id
order by cat_name, value_id
来自以下型号:
class Context_value(db.Model):
__tablename__ = 'context_values'
id = db.Column(...)
cat_id = db.Column(db.SmallInteger, db.ForeignKey('context_categories.id',
ondelete="RESTRICT", onupdate="CASCADE"), unique=False, index=True, nullable=False)
verified = db.Column(db.Boolean)
context_value_r1 = db.relationship('Context_value_r1', backref='context_values', lazy='dynamic')
etc.
class Context_category(db.Model):
__tablename__ = 'context_categories'
id = db.Column(db.SmallInteger, primary_key=True)
...
name = db.Column(db.String(100), nullable=False)
__table_args__ = (db.Index('unq_context_categories_name', '...', 'name', unique=True),)
ctx_values = db.relationship('Context_value', backref='context_categories', lazy='select')
SQL 命令在数据库管理员 space 中执行其预期的工作(在物化视图中组合相关值以进行快速查找),但我无法在ORM 语法。
db.join(
db.select(Context_category).
outerjoin(Context_category.ctx_values).
where(Context_value.verified==True
),
db.select(Context_value).
outerjoin(Context_value.context_rel1).
outerjoin(Context_value.context_rel2).
outerjoin(Context_value.context_rel3).
outerjoin(Context_value.context_rel4).
all(),
isouter=True
)
生成以下错误(仅消息结尾):
File "c:\users\...\app\models\mod_context.py", line 638, in ...
db.select(Context_category).\
File "<string>", line 2, in select
File "<string>", line 2, in __init__
File "c:\users\...\venv\lib\site-packages\sqlalchemy\util\deprecations.py", line 139, in warned
return fn(*args, **kwargs)
File "c:\users\...\venv\lib\site-packages\sqlalchemy\sql\selectable.py", line 3114, in __init__
for c in columns:
TypeError: 'DefaultMeta' object is not iterable
任何帮助或建议将不胜感激。
请在下面找到一个快速但完整的示例,您可以使用它来找到您的解决方案:
## Imports
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
## Configuration
app = Flask(__name__)
_db_uri = "sqlite:///:memory:"
app.config["SQLALCHEMY_DATABASE_URI"] = _db_uri
app.config["SQLALCHEMY_ECHO"] = True
db = SQLAlchemy(app)
# ## Model definitions
class Context_value(db.Model):
__tablename__ = "context_values"
id = db.Column(db.Integer, primary_key=True)
cat_id = db.Column(
db.SmallInteger,
db.ForeignKey("context_categories.id", ondelete="RESTRICT", onupdate="CASCADE"),
unique=False,
index=True,
nullable=False,
)
verified = db.Column(db.Boolean)
context_categories = db.relationship(
"Context_category", back_populates="ctx_values"
)
context_rel1 = db.relationship(
"Context_value_r1", backref="context_values", lazy="dynamic"
)
context_rel2 = db.relationship(
"Context_value_r2", backref="context_values", lazy="dynamic"
)
class Context_category(db.Model):
__tablename__ = "context_categories"
id = db.Column(db.SmallInteger, primary_key=True)
name = db.Column(db.String(100), nullable=False)
# __table_args__ = (db.Index('unq_context_categories_name', '...', 'name', unique=True),)
ctx_values = db.relationship(
"Context_value", back_populates="context_categories", lazy="select"
)
class Context_value_r1(db.Model):
__tablename__ = "context_value_r1"
id = db.Column(db.Integer, primary_key=True)
value_id = db.Column(
db.ForeignKey("context_values.id", ondelete="RESTRICT", onupdate="CASCADE"),
unique=False,
index=True,
nullable=False,
)
value_r1 = db.Column(db.Integer)
class Context_value_r2(db.Model):
__tablename__ = "context_value_r2"
id = db.Column(db.Integer, primary_key=True)
value_id = db.Column(
db.ForeignKey("context_values.id", ondelete="RESTRICT", onupdate="CASCADE"),
unique=False,
index=True,
nullable=False,
)
value_r2 = db.Column(db.Integer)
def _main():
with app.app_context():
db.drop_all()
db.create_all()
print("=" * 80)
# aliases for readability
cv = Context_value
cs = Context_category
ctx_j = (
db.select(cv.id, cs.name)
.select_from(cv)
.outerjoin(cs, cv.context_categories)
.where(cv.verified == True)
).subquery("ctx_j")
# aliases for readability
v = Context_value
r1 = Context_value_r1
r2 = Context_value_r2
# sub-select
x = (
db.select(
v.id.label("value_id"),
r1.value_r1.label("r1"),
r2.value_r2.label("r2"),
)
.select_from(v)
.outerjoin(r1, v.context_rel1)
.outerjoin(r2, v.context_rel2)
).subquery("x")
# final query
q = (
db.select(ctx_j, x)
.outerjoin(x, ctx_j.c.id == x.c.value_id)
.order_by(ctx_j.c.name, x.c.value_id)
)
print(q)
if __name__ == "__main__":
_main()
q
的打印输出应如下所示:
SELECT ctx_j.id,
ctx_j.name,
x.value_id,
x.r1,
x.r2
FROM
(SELECT context_values.id AS id,
context_categories.name AS name
FROM context_values
LEFT OUTER JOIN context_categories ON context_categories.id = context_values.cat_id
WHERE context_values.verified = true) AS ctx_j
LEFT OUTER JOIN
(SELECT context_values.id AS value_id,
context_value_r1.value_r1 AS r1,
context_value_r2.value_r2 AS r2
FROM context_values
LEFT OUTER JOIN context_value_r1 ON context_values.id = context_value_r1.value_id
LEFT OUTER JOIN context_value_r2 ON context_values.id = context_value_r2.value_id) AS x ON ctx_j.id = x.value_id
ORDER BY ctx_j.name,
x.value_id
我在将有效的 SQL 文本转换为 ORM 命令时遇到问题...
select ctx_j.name as cat_name, x.id as value_id, x.value_r1 as r1,
x.value_r2 as r2, x.value_r3 as r3, x.value_r4 as r4
from (
select cv.id as id, cs.name as name
from context_values cv
left join context_categories cs
on cv.cat_id=cs.id
where cv.verified is True
) as ctx_j
left join (
select t3.id as id, value_r1, value_r2, value_r3, value_r4
from (((((
context_values as v
left join context_value_r1 as r1 on v.id=r1.value_id) as t1
left join context_value_r2 as r2 on t1.id=r2.value_id) as t2
left join context_value_r3 as r3 on t2.id=r3.value_id) as t3
left join context_value_r4 as r4 on t3.id=r4.value_id
) as x on ctx_j.id=x.id
order by cat_name, value_id
来自以下型号:
class Context_value(db.Model):
__tablename__ = 'context_values'
id = db.Column(...)
cat_id = db.Column(db.SmallInteger, db.ForeignKey('context_categories.id',
ondelete="RESTRICT", onupdate="CASCADE"), unique=False, index=True, nullable=False)
verified = db.Column(db.Boolean)
context_value_r1 = db.relationship('Context_value_r1', backref='context_values', lazy='dynamic')
etc.
class Context_category(db.Model):
__tablename__ = 'context_categories'
id = db.Column(db.SmallInteger, primary_key=True)
...
name = db.Column(db.String(100), nullable=False)
__table_args__ = (db.Index('unq_context_categories_name', '...', 'name', unique=True),)
ctx_values = db.relationship('Context_value', backref='context_categories', lazy='select')
SQL 命令在数据库管理员 space 中执行其预期的工作(在物化视图中组合相关值以进行快速查找),但我无法在ORM 语法。
db.join(
db.select(Context_category).
outerjoin(Context_category.ctx_values).
where(Context_value.verified==True
),
db.select(Context_value).
outerjoin(Context_value.context_rel1).
outerjoin(Context_value.context_rel2).
outerjoin(Context_value.context_rel3).
outerjoin(Context_value.context_rel4).
all(),
isouter=True
)
生成以下错误(仅消息结尾):
File "c:\users\...\app\models\mod_context.py", line 638, in ...
db.select(Context_category).\
File "<string>", line 2, in select
File "<string>", line 2, in __init__
File "c:\users\...\venv\lib\site-packages\sqlalchemy\util\deprecations.py", line 139, in warned
return fn(*args, **kwargs)
File "c:\users\...\venv\lib\site-packages\sqlalchemy\sql\selectable.py", line 3114, in __init__
for c in columns:
TypeError: 'DefaultMeta' object is not iterable
任何帮助或建议将不胜感激。
请在下面找到一个快速但完整的示例,您可以使用它来找到您的解决方案:
## Imports
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
## Configuration
app = Flask(__name__)
_db_uri = "sqlite:///:memory:"
app.config["SQLALCHEMY_DATABASE_URI"] = _db_uri
app.config["SQLALCHEMY_ECHO"] = True
db = SQLAlchemy(app)
# ## Model definitions
class Context_value(db.Model):
__tablename__ = "context_values"
id = db.Column(db.Integer, primary_key=True)
cat_id = db.Column(
db.SmallInteger,
db.ForeignKey("context_categories.id", ondelete="RESTRICT", onupdate="CASCADE"),
unique=False,
index=True,
nullable=False,
)
verified = db.Column(db.Boolean)
context_categories = db.relationship(
"Context_category", back_populates="ctx_values"
)
context_rel1 = db.relationship(
"Context_value_r1", backref="context_values", lazy="dynamic"
)
context_rel2 = db.relationship(
"Context_value_r2", backref="context_values", lazy="dynamic"
)
class Context_category(db.Model):
__tablename__ = "context_categories"
id = db.Column(db.SmallInteger, primary_key=True)
name = db.Column(db.String(100), nullable=False)
# __table_args__ = (db.Index('unq_context_categories_name', '...', 'name', unique=True),)
ctx_values = db.relationship(
"Context_value", back_populates="context_categories", lazy="select"
)
class Context_value_r1(db.Model):
__tablename__ = "context_value_r1"
id = db.Column(db.Integer, primary_key=True)
value_id = db.Column(
db.ForeignKey("context_values.id", ondelete="RESTRICT", onupdate="CASCADE"),
unique=False,
index=True,
nullable=False,
)
value_r1 = db.Column(db.Integer)
class Context_value_r2(db.Model):
__tablename__ = "context_value_r2"
id = db.Column(db.Integer, primary_key=True)
value_id = db.Column(
db.ForeignKey("context_values.id", ondelete="RESTRICT", onupdate="CASCADE"),
unique=False,
index=True,
nullable=False,
)
value_r2 = db.Column(db.Integer)
def _main():
with app.app_context():
db.drop_all()
db.create_all()
print("=" * 80)
# aliases for readability
cv = Context_value
cs = Context_category
ctx_j = (
db.select(cv.id, cs.name)
.select_from(cv)
.outerjoin(cs, cv.context_categories)
.where(cv.verified == True)
).subquery("ctx_j")
# aliases for readability
v = Context_value
r1 = Context_value_r1
r2 = Context_value_r2
# sub-select
x = (
db.select(
v.id.label("value_id"),
r1.value_r1.label("r1"),
r2.value_r2.label("r2"),
)
.select_from(v)
.outerjoin(r1, v.context_rel1)
.outerjoin(r2, v.context_rel2)
).subquery("x")
# final query
q = (
db.select(ctx_j, x)
.outerjoin(x, ctx_j.c.id == x.c.value_id)
.order_by(ctx_j.c.name, x.c.value_id)
)
print(q)
if __name__ == "__main__":
_main()
q
的打印输出应如下所示:
SELECT ctx_j.id,
ctx_j.name,
x.value_id,
x.r1,
x.r2
FROM
(SELECT context_values.id AS id,
context_categories.name AS name
FROM context_values
LEFT OUTER JOIN context_categories ON context_categories.id = context_values.cat_id
WHERE context_values.verified = true) AS ctx_j
LEFT OUTER JOIN
(SELECT context_values.id AS value_id,
context_value_r1.value_r1 AS r1,
context_value_r2.value_r2 AS r2
FROM context_values
LEFT OUTER JOIN context_value_r1 ON context_values.id = context_value_r1.value_id
LEFT OUTER JOIN context_value_r2 ON context_values.id = context_value_r2.value_id) AS x ON ctx_j.id = x.value_id
ORDER BY ctx_j.name,
x.value_id