代码之家  ›  专栏  ›  技术社区  ›  Danila Ganchar

sqlalchemy按json字段筛选

  •  2
  • Danila Ganchar  · 技术社区  · 6 年前

    我有一个模特 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行:其中(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行:其中cast((example.json_field-> “id”)作为整数)=1

    如你所见 where clause > , <= 等)条件。谢谢你的帮助。

    1 回复  |  直到 6 年前
        1
  •  27
  •   Ilja Everilä    6 年前

    炼金术 SQLAlchemy db gives access 从…到…等 sqlalchemy sqlalchemy.orm ,等等 db.JSON generic JSON type 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 如果强制转换仅从文本字符串起作用,则不能显式调用修饰符。

        2
  •  5
  •   Ryabchenko Alexander    5 年前

    from sqlalchemy import text
    
    db.session.query(Example).filter(text("CAST(json_field->>'id' AS INTEGER) = 1")
    
        3
  •  0
  •   eastonsuo    6 年前

    filter(json_obj["key"] ... ) 它将像sql一样转换为sql model_name.json_obj -> 'key'

    如果你使用 filter(json_obj["key"].astext ...) ,sql将是 model_name.json_obj ->> 'key' ,结果是一个字符串对象。