SQLAlchemy:通过JSON列中的键进行过滤

8

SQLAlchemy版本:1.2.10,PostgreSQL版本:10-something。
我遵循这里的文档示例。

In [1]: import sqlalchemy as sa

In [2]: from nimble_core.backend.persistence.pg import PG_META_DATA

In [3]: data_table = sa.Table('data_table', PG_META_DATA,
   ...:     sa.Column('id', sa.Integer, primary_key=True),
   ...:     sa.Column('data', sa.JSON)
   ...: )

In [4]: data_table.create()

In [5]: with PG_ENGINE.connect() as conn:
   ...:     conn.execute(
   ...:         data_table.insert(),
   ...:         data = {"key1": "value1", "key2": "value2"}
   ...:     )
   ...:

地点:

In [10]: PG_ENGINE
Out[10]: Engine(postgresql://nimble:***@localhost:5432/nimble)

In [11]: PG_META_DATA
Out[11]: MetaData(bind=Engine(postgresql://nimble:***@localhost:5432/nimble))

In [12]: PG_META_DATA.sorted_tables
Out[12]:
[Table('data_table', MetaData(bind=Engine(postgresql://nimble:***@localhost:5432/nimble)), Column('id', Integer(), table=<data_table>, primary_key=True, nullable=False), Column('data', JSON(), table=<data_table>), schema=None)]

插入操作完成后,该表只有一行:

    In [14]: PG_ENGINE.execute(sa.select([data_table])).fetchall()
    Out[14]: [(1, {u'key2': u'value2', u'key1': u'value1'})]

我接下来要做的是按照JSON列中特定键下的值查询行,可以参考这个示例:

In [17]: PG_ENGINE.execute(
    ...:     sa.select([data_table]).where(
    ...:         data_table.c.data['key1'].astext == 'value1'
    ...:     )
    ...: )
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-17-3c4db8afed3f> in <module>()
      1 PG_ENGINE.execute(
      2     sa.select([data_table]).where(
----> 3         data_table.c.data['key1'].astext == 'value1'
      4     )
      5 )

/Users/psih/Work/nimble-server/runtime/lib/python2.7/site-packages/sqlalchemy/sql/elements.pyc in __getattr__(self, key)
    686                     type(self).__name__,
    687                     type(self.comparator).__name__,
--> 688                     key)
    689             )
    690

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

显然,data_table.c.data['key1'] 的类型是一些(sqlalchemy.sql.elements.BinaryExpression)没有 astext 属性。这是否意味着文档有误?

1
“这是否意味着文档有误?” 不,您只是阅读了两种不同类型的文档,并将它们混淆了一些。 - Ilja Everilä
2个回答

12

您正在使用没有astextsqlalchemy.types.JSON。请改用sqlalchemy.dialects.postgresql.JSON

import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

data_table = sa.Table('data_table', PG_META_DATA,
    sa.Column('id', sa.Integer, primary_key=True),
    sa.Column('data', postgresql.JSON)
)

谢谢,这正是我所需要的。 - Anton Koval'
2
此外,您可以使用as_string()而不是astext,如@r-m-n提供的sqlalchemy.types.JSON链接中所述。 - EliA

1
你可以在SQLAlchemy的过滤器中使用原始SQL。
from sqlalchemy import text

db.session.query(DataTable).filter(text("data->['key1'] = 'value1'")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接