【发布时间】:2019-11-24 04:19:38
【问题描述】:
我一直在查看 SQLAlchemy api,它非常复杂,所以我想我会在这里询问是否有人可以以某种易于理解的格式向我解释这一点。
我正在围绕 O365 python api 编写一个包装器,用于编写 Office365 REST api 查询,其语法类似于 SQLAlchemy。
O365 提供了一个流畅的查询类,如下所示:
Message.new_query().on_attribute("subject").contains("Hello Friend!").chain("and").on_attribute("from").equals("some_address@gmail.com")
我目前有一些可以工作的东西,看起来像这样:
Message.where(Subject.contains("Hello Friend!") & (From == "some_address@gmail.com")).execute()
确切的代码并不相关,但简而言之,它通过为运算符实现魔术方法并添加额外的方法(例如 .contains())来构建 BooleanExpression 对象。例如:
From == "some_address@gmail.com"
将返回一个 BooleanExpression。
BooleanExpression 对象然后与“&”或“|”组合返回 BooleanExpressionClause 对象的运算符,这些对象基本上是一个 BooleanExpression 对象列表,用于跟踪每 2 个表达式连接的运算符。
最后,.where() 方法使用单个 BooleanExpressionClause 并在后台为它构建一个流畅的查询。
到目前为止一切顺利。
所以我遇到的障碍涉及优先分组。
假设我想要所有带有“嗨!”的消息地址中包含“john”或地址中包含“doe”的发件人在其主题中。如果我有这样的查询:
From.contains("john") | From.contains("doe") & Subject.contains("Hi!")
我会从地址中带有“john”的任何人那里收到每条消息,因为 Microsoft 的 API 实际上将生成的 REST 请求读取为:
From.contains("john") | (From.contains("doe") & Subject.contains("Hi!"))
当我想要的是:
(From.contains("john") | From.contains("doe")) & Subject.contains("Hi!")
但是,如果我只是使用我当前的 API 编写它,那将与完全不使用任何括号编写它没有什么不同,因为据我所知,对于 python,第一个示例(没有优先级组) ,第三个例子(我想要的优先级组)看起来完全一样,因为解释器只是从左到右读取这样的子句。
这终于让我想到了我的问题。 SQLAlchemy 能够以某种方式理解优先级组,但我一生都无法理解它是如何做到的。
例如:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy import engine, Column
from sqlalchemy.types import Integer, String
engine = engine("some_engine_url")
Base = declarative_base()
s = sessionmaker(bind=engine)()
class Person(Base):
__tablename__ = "person"
id = Column(Integer, primary_key=True)
name = Column(String)
sex = Column(String(1))
print(s.query(Person).filter( (Person.name == "john") | (Person.name == "doe") & (Person.sex == "M") ))
print(s.query(Person).filter( ((Person.name == "john") | (Person.name == "doe")) & (Person.sex == "M") ))
这些打印语句分别返回,
SELECT person.id AS person_id, person.name AS person_name, person.sex AS person_sex
FROM person
WHERE person.name = ? OR person.name = ? AND person.sex = ?
和
SELECT person.id AS person_id, person.name AS person_name, person.sex AS person_sex
FROM person
WHERE (person.name = ? OR person.name = ?) AND person.sex = ?
SQLAlchemy 内部究竟是如何区分这两个过滤子句的呢?据我所知,python 应该以相同的方式处理它们,但显然那里有一些我不知道的魔法 的。
我怎样才能复制这种行为?
非常感谢!
【问题讨论】:
标签: python python-3.x sqlalchemy