我有json column
的模特。模型和数据示例:
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://...'
db = SQLAlchemy()
db.init_app(app)
app.app_context().push()
class Example(db.Model):
id = db.Column(db.Integer(), nullable=False, primary_key=True, )
json_field = db.Column(db.JSON())
db.create_all()
db.session.add(Example(json_field={'id': None}))
db.session.add(Example(json_field={'id': 1}))
db.session.add(Example(json_field={'id': 50}))
db.session.add(Example(json_field={}))
db.session.commit()
现在我尝试在id == 1
处查找记录:
query = db.session.query(Example).filter(Example.json_field['id'] == 1)
print(query.all())
我收到下一个错误:
sqlalchemy.exc.ProgrammingError:(psycopg2.ProgrammingError)运算符 不存在:json =整数第3行:WHERE(example.json_field-> 'id')= 1
原因。查看生成的查询:
SELECT example.id AS example_id, example.json_field AS example_json_field
FROM example
WHERE (example.json_field -> %(json_field_1)s) = %(param_1)s
但是在我的情况下,正确的查询应该是这样的:
SELECT * FROM example WHERE CAST(json_field->>'id' AS INTEGER) = 1;
我该怎么做?
我尝试使用cast,但未成功:
print(
db.session.query(Example).filter(
cast(Example.json_field['id'], Integer) == 1
).all()
)
错误:
sqlalchemy.exc.ProgrammingError:(psycopg2.ProgrammingError)无法 将类型json转换为整数第3行:WHERE CAST(((example.json_field-> 'id')AS INTEGER)= 1
您可以看到where clause
仍然是错误的。另外,我需要使用范围(>
,<=
等)条件。感谢您的帮助。
答案 0 :(得分:7)
Flask-SQLAlchemy的SQLAlchemy
对象–通常命名为db
– gives access到sqlalchemy
和sqlalchemy.orm
等的函数等,db.JSON
是generic JSON
type,不提供特定于Postgresql的运算符。您应该改用sqlalchemy.dialects.postgresql.JSON
:
from sqlalchemy.dialects.postgresql import JSON
class Example(db.Model):
id = db.Column(db.Integer(), nullable=False, primary_key=True, )
json_field = db.Column(JSON)
使用适当的类型后,您必须先显式转换JSON to text,然后将其转换为整数:
db.session.query(Example).\
filter(Example.json_field['id'].astext.cast(Integer) == 1)
这将产生所需的谓词
CAST(json_field->>'id' AS INTEGER) = 1
这同样适用于所有不能直接从json
强制转换的类型。 SQLAlchemy曾经为astext
和cast()
的组合提供快捷方式,但是在1.1版及更高版本中已将其删除:
版本1.1中的更改:
ColumnElement.cast()
对象上的JSON
运算符现在要求显式调用JSON.Comparator.astext
修饰符(如果强制转换仅从文本字符串起作用)。
答案 1 :(得分:4)
您还可以在过滤器中使用原始sql
from sqlalchemy import text
db.session.query(Example).filter(text("CAST(json_field->>'id' AS INTEGER) = 1")
答案 2 :(得分:0)
如果仅使用filter(json_obj["key"] ... )
,它将转换为sql
model_name.json_obj -> 'key'
(仍然是json对象)
如果您使用filter(json_obj["key"].astext ...)
,则SQL将为
model_name.json_obj ->> 'key'
,结果是一个字符串对象。