在Pony ORM中逐步构建查询

3
我正在评估从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模型类型上的各种操作符重载只是返回一个查询组件的树,这些子树可以通过进一步的操作符重载进行组合。同时,可以用&|操作符链接多个查询组件,例如:model.Entry.select().where(some_test() & some_other_test())。这非常有用,因为我的许多过滤查询都是以模块化的方式组成的,大部分底层查询部分经常被重复使用,很多也是不平凡的(例如上面的例子)。
然而,在Pony ORM中,似乎只有(相当聪明的!)AST生成器解析器和原始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的相关部分,或者通过一种机制,我将查询传递给另一个子查询进行过滤。)
1个回答

4
在PonyORM中,您可以通过两种方式逐步组成查询。第一种是查询的filter方法:(链接)。请注意保留HTML标记。
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从句添加子表达式的功能。


太棒了,这正是我所需要的。非常感谢! - fluffy

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