簡體   English   中英

sqlalchemy 按 json 字段過濾

[英]sqlalchemy filter by json field

我有 model 和json column model和數據示例:

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 = integer 第 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 轉換為 integer 第 3 行:WHERE CAST((example.json_field -> 'id') AS INTEGER) = 1

如您所見where clause仍然錯誤。 我還需要使用范圍( ><=等)條件。 感謝幫助。

燒瓶的SQLAlchemy的SQLAlchemy對象-通常稱為db - 可以訪問,從功能等sqlalchemysqlalchemy.orm ,所以db.JSON通用的JSON類型不提供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顯式轉換為文本,然后再轉換為整數:

db.session.query(Example).\
    filter(Example.json_field['id'].astext.cast(Integer) == 1)

這將產生所需的謂詞

CAST(json_field->>'id' AS INTEGER) = 1

這同樣適用於所有不能直接從json SQLAlchemy 曾經為astextcast()的組合提供快捷方式,但它已在 1.1 及更高版本中刪除:

在 1.1 版更改: JSON對象上的ColumnElement.cast()運算符現在要求顯式調用JSON.Comparator.astext修飾符,如果轉換僅適用於文本字符串。

您還可以在過濾器中使用原始 sql

from sqlalchemy import text

db.session.query(Example).filter(text("CAST(json_field->>'id' AS INTEGER) = 1")

我想你可以使用這個表達式:

db.session.query(Example).filter(
    Example.json_field.op("->>")("id").cast(Integer) == 1
)

如果你只使用filter(json_obj["key"] ... )它會像model_name.json_obj -> 'key'一樣轉換為 sql ,它仍然是一個 json 對象,

如果您使用filter(json_obj["key"].astext ...) ,sql 將是model_name.json_obj ->> 'key' ,結果是一個字符串對象。

如果遇到

AttributeError: Neither 'BinaryExpression' object nor 'Comparator' object has an attribute 'astext'

與@DanilaGanchar和I相同, 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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM