在 Pony ORM 中增量构建查询
Building a query incrementally in Pony ORM
我正在评估从 peewee 到 Pony ORM 的转换。 peewee 中可用的一件好事是能够从这样的部分组成查询:
def Entry(BaseModel):
# peewee fields go here
def where_entry_category(category, recurse=False):
""" Generate a where clause for a particular category """
if category or not recurse:
cat_where = (Entry.category == str(category))
if recurse:
# We're recursing and aren't in /, so add the prefix clause
cat_where = cat_where | (
Entry.category.startswith(str(category) + '/'))
else:
cat_where = True
return cat_where
query = Entry.select().where(where_entry_category("test"))
它的工作方式是各种运算符在 peewee 模型类型上重载简单地 return 一棵查询组件树,这些子树可以由进一步的运算符重载组成。使用 &
或 |
运算符链接在一起的多个查询组件也是一件简单的事情,例如model.Entry.select().where(some_test() & some_other_test())
。这非常有用,因为我的许多过滤查询都是以模块化方式组合的,并且大多数底层查询部分经常被重用,而且很多都是重要的(例如上面的示例)。
然而,在 Pony ORM 中,似乎只有(非常聪明!)AST generator parser 和原始 SQL。由于原始 SQL 表单无法让我直接传递必要的查询部分,因此如果可能的话,我更愿意使用一些更高级别的查询构建功能。
如果我尝试将查询部分定义为模型上的方法,例如:
class Entry(db.Entity):
...
def in_category(self, category, recurse=False):
# return a test on the parameters
orm.select(entry for entry in model.Entry if entry.in_category('foo', True))
我得到 NotImplementedError
,不足为奇。
是否有从现有部分构建查询表达式并传递到 SQL 查询构建器的机制? (也许通过自己构建 AST 并将其传递到 Pony 的相关部分,或者有一种机制,我可以传递一个查询以被另一个子查询过滤。)
在 PonyORM 中,您可以通过两种方式逐步编写查询。第一个是查询的 filter
方法:
def where_entry_category(query, category, recourse)
if category:
category = str(category)
if recurse:
query = query.filter(lambda x: x.category == category or
x.category.startswith(category + '/')
else:
query = query.filter(lambda x: x.category == category)
return query
query = Entry.select()
query = where_entry_category(query, "test")
从 0.7.6 版开始,也可以使用以前的查询作为新查询的来源:
def where_entry_category(query, category, recourse)
if category:
category = str(category)
if recurse:
query = select(x for x in query
if x.category == category or
x.category.startswith(category + '/'))
else:
query = select(x for x in query if x.category == category)
return query
你可能遇到的唯一问题是,如果你想逐渐构建具有可变数量子表达式的 or
子句,此时 Pony 没有 API。可能我们会在未来的版本中逐渐增加向 or
子句添加子表达式的可能性。
我正在评估从 peewee 到 Pony ORM 的转换。 peewee 中可用的一件好事是能够从这样的部分组成查询:
def Entry(BaseModel):
# peewee fields go here
def where_entry_category(category, recurse=False):
""" Generate a where clause for a particular category """
if category or not recurse:
cat_where = (Entry.category == str(category))
if recurse:
# We're recursing and aren't in /, so add the prefix clause
cat_where = cat_where | (
Entry.category.startswith(str(category) + '/'))
else:
cat_where = True
return cat_where
query = Entry.select().where(where_entry_category("test"))
它的工作方式是各种运算符在 peewee 模型类型上重载简单地 return 一棵查询组件树,这些子树可以由进一步的运算符重载组成。使用 &
或 |
运算符链接在一起的多个查询组件也是一件简单的事情,例如model.Entry.select().where(some_test() & some_other_test())
。这非常有用,因为我的许多过滤查询都是以模块化方式组合的,并且大多数底层查询部分经常被重用,而且很多都是重要的(例如上面的示例)。
然而,在 Pony ORM 中,似乎只有(非常聪明!)AST generator parser 和原始 SQL。由于原始 SQL 表单无法让我直接传递必要的查询部分,因此如果可能的话,我更愿意使用一些更高级别的查询构建功能。
如果我尝试将查询部分定义为模型上的方法,例如:
class Entry(db.Entity):
...
def in_category(self, category, recurse=False):
# return a test on the parameters
orm.select(entry for entry in model.Entry if entry.in_category('foo', True))
我得到 NotImplementedError
,不足为奇。
是否有从现有部分构建查询表达式并传递到 SQL 查询构建器的机制? (也许通过自己构建 AST 并将其传递到 Pony 的相关部分,或者有一种机制,我可以传递一个查询以被另一个子查询过滤。)
在 PonyORM 中,您可以通过两种方式逐步编写查询。第一个是查询的 filter
方法:
def where_entry_category(query, category, recourse)
if category:
category = str(category)
if recurse:
query = query.filter(lambda x: x.category == category or
x.category.startswith(category + '/')
else:
query = query.filter(lambda x: x.category == category)
return query
query = Entry.select()
query = where_entry_category(query, "test")
从 0.7.6 版开始,也可以使用以前的查询作为新查询的来源:
def where_entry_category(query, category, recourse)
if category:
category = str(category)
if recurse:
query = select(x for x in query
if x.category == category or
x.category.startswith(category + '/'))
else:
query = select(x for x in query if x.category == category)
return query
你可能遇到的唯一问题是,如果你想逐渐构建具有可变数量子表达式的 or
子句,此时 Pony 没有 API。可能我们会在未来的版本中逐渐增加向 or
子句添加子表达式的可能性。