简体   繁体   English

SQLAlchemy:如何用字典值过滤?

[英]SQLAlchemy: how to filter with dictionary value?

I have a database table like this:我有一个这样的数据库表:

+-------------------------------------------------------------+
| id | res_id    | path                   | overrides         |
|-------------------------------------------------------------|
| 1  | res_1     | res_1                  | {"enabled": True} |
| 2  | res_1.1   | res_1.res_1.1          | {"enabled": False}|
| 3  | res_1.2   | res_1.res_1.2          | {"enabled": False}|
| 4  | res_1.1.1 | res_1.res_1.1.res_1.1.1| {"enabled": False}|
+-------------------------------------------------------------+

The overrides is for setting a breaking point to inheritance. So, if I query the res_1.1.1 m I'd normally get also resources 1 & 2, because of the inheritance. But now, there is "enabled": True in 1 and it doesn't inherit anywhere, so the query would return only 2 & 4. overrides是为了将断点设置为 inheritance。因此,如果我查询res_1.1.1 m,由于 inheritance,我通常还会获得资源 1 和 2。但是现在, "enabled": True in 1 and它不会在任何地方继承,因此查询只会返回 2 和 4。

The question is, how can I filter out objects where the overrides is "enabled": True ?问题是,如何过滤掉“启用” overrides的对象"enabled": True I've tried eg this:我试过这样的:
.filter(MyModel.overrides["enabled"] is not True) , this doesn't seem to work. .filter(MyModel.overrides["enabled"] is not True) ,这似乎不起作用。

I've also tried using dictionary methods get() , values() and keys() , but they give me an error, eg AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with MyModel.overrides has an attribute 'get' .我也尝试过使用字典方法get()values()keys() ,但它们给我一个错误,例如AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with MyModel.overrides has an attribute 'get'

The field overrides in a JSONB -field.该字段在JSONB字段中overrides

There is two things here you're missing.这里有两件事你错过了。

Firstly, .filter(col is not True) cannot be compiled by SQLAlchemy, I recommend you use .filter(col == False) or .filter(col.is_(False)) .首先, .filter(col is not True)不能被SQLAlchemy编译,我推荐你使用.filter(col == False)或者.filter(col.is_(False))

Then to access the value inside the the JSONB dict, you need to cast it to a SQL type, for instance with .as_boolean() .然后要访问 JSONB dict 中的值,您需要将其转换为 SQL 类型,例如使用.as_boolean()

Putting both of those together, we get:将两者放在一起,我们得到:

stmt = (
    select(MyModel)
    .filter(MyModel.overrides["enabled"].as_boolean() == False)
)

Full script demo:完整脚本演示:

import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

metadata_obj = sa.MetaData()

t = sa.Table(
    "t72632977",
    metadata_obj,
    sa.Column("id", sa.Integer, primary_key=True),
    sa.Column("res_id", sa.String),
    sa.Column("path", sa.String),
    sa.Column("overrides", postgresql.JSONB),
)

engine = sa.create_engine(
    "postgresql+psycopg2://postgres:postgres@localhost:5432/postgres",
    echo=True,
    future=True,
)

metadata_obj.create_all(engine)

with engine.begin() as con:
    con.execute(
        sa.insert(t),
        [
            {
                "res_id": "res_1",
                "path": "res_1",
                "overrides": {"enabled": True},
            },
            {
                "res_id": "res_1.1",
                "path": "res_1.res_1.1",
                "overrides": {"enabled": False},
            },
            {
                "res_id": "res_1.2",
                "path": "res_1.res_1.2",
                "overrides": {"enabled": False},
            },
            {
                "res_id": "res_1.1.1",
                "path": "res_1.res_1.1.res_1.1.1",
                "overrides": {"enabled": False},
            },
        ],
    )

with engine.connect() as con:
    r = con.execute(
        sa.select(t).filter(t.c.overrides["enabled"].as_boolean() == False)
    )
    print(r.all())

# emits
# SELECT t72632977.id, t72632977.res_id, t72632977.path, t72632977.overrides 
# FROM t72632977 
# WHERE CAST((t72632977.overrides ->> %(overrides_1)s) AS BOOLEAN) = false

# returns
# [
#     (2, 'res_1.1', 'res_1.res_1.1', {'enabled': False}),
#     (3, 'res_1.2', 'res_1.res_1.2' , {'enabled': False}),
#     (4, 'res_1.1.1', 'res_1.res_1.1.res_1.1.1', {'enabled': False}),
# ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM