【问题标题】:Ponyorm: filtering objects by multiple joined values in a JOINPonyorm:通过 JOIN 中的多个连接值过滤对象
【发布时间】:2020-02-23 23:12:40
【问题描述】:

我正在尝试实现一个标签过滤机制,其中项目可以有任意数量的与之关联的标签,并且我希望能够找到具有任何或所有请求标签的项目。

我的架构是这样的:

class Item(db.Entity):
    tags = orm.Set("ItemTag")

class ItemTag(db.Entity):
    item = orm.Required(Item)
    tag = orm.Required(str)
    orm.composite_key(item, tag)
    orm.composite_key(tag, item)

我可以使用单个标签轻松过滤现有查询:

def filter_query_tag(query, tag:str):
    return orm.select(i for i in query for t in i.tags if t.key == tag)

而且我可以轻松找到带有 任何 标记的项目:

def filter_query_any_tag(query, tags:typing.Union(set,list,tuple)):
    return orm.select(i for i in query for t in i.tags if t.key in tags)

但尝试构建查找所有标签的查询会引发错误:

def filter_query_all_tags(query, tags:typing.Union(set,list,tuple)):
    for tag in tags:
        query = orm.select(i for i in query for t in i.tags if t.key == tag)
    return query

结果:

  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/core.py", line 5562, in select
    return make_query(args, frame_depth=cut_traceback_depth+1)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/core.py", line 5558, in make_query
    return Query(code_key, tree.code, globals, locals, cells, left_join)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/core.py", line 5717, in __init__
    translator = translator_cls(tree_copy, None, code_key, filter_num, extractors, vars, vartypes.copy(), left_join=left_join)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/sqltranslation.py", line 222, in __init__
    translator.init(tree, parent_translator, code_key, filter_num, extractors, vars, vartypes, left_join, optimize)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/sqltranslation.py", line 396, in init
    tableref = translator.sqlquery.add_tableref(name_path, parent_tableref, attr)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/sqltranslation.py", line 1211, in add_tableref
    assert name_path not in sqlquery.tablerefs
AssertionError

据推测,问题在于将多个连接名称映射到同一个表时存在问题,这可能是 ponyorm 中的一个错误。但是,我怀疑可能有更好的方法来构建查询,而无需首先执行多个连接和过滤器。

我尝试使用orm.left_join 而不是orm.select,如下所示:

def filter_query_all_tags(query, tags:typing.Union(set,list,tuple)):
    for tag in tags:
        query = orm.left_join(i for i in query for t in i.tags if t.key == tag)
    return query

在这种情况下,我可以同时过滤 两个 标签,但如果我添加第三个标签,我会得到:

  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/core.py", line 5566, in left_join
    return make_query(args, frame_depth=cut_traceback_depth+1, left_join=True)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/core.py", line 5558, in make_query
    return Query(code_key, tree.code, globals, locals, cells, left_join)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/core.py", line 5717, in __init__
    translator = translator_cls(tree_copy, None, code_key, filter_num, extractors, vars, vartypes.copy(), left_join=left_join)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/sqltranslation.py", line 222, in __init__
    translator.init(tree, parent_translator, code_key, filter_num, extractors, vars, vartypes, left_join, optimize)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/sqltranslation.py", line 343, in init
    names, try_extend_prev_query=not i)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/sqltranslation.py", line 598, in process_query_qual
    subquery_ast = prev_translator.construct_subquery_ast(prev_limit, prev_offset, aliases=aliases)
  File "/Users/fluffy/.local/share/virtualenvs/Publ-FUB3ZG92/lib/python3.7/site-packages/pony/orm/sqltranslation.py", line 625, in construct_subquery_ast
    assert not star and len(aliases) == len(select_ast) - 1
AssertionError

在 ponyorm 中是否有一个原始或惯用的表达式允许我指定集合的​​ 所有 值必须存在于任何给定 ItemItemTag 值中?

【问题讨论】:

标签: python ponyorm


【解决方案1】:

这似乎有效:

def filter_query_all_tags(query, tags:typing.Union(set,list,tuple)):
    for tag in tags:
        query = query.filter(lambda i: orm.exists(t for t in i.tags if t.key == tag))
    return query

但是,这似乎可能会更好。

【讨论】:

    猜你喜欢
    • 2020-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 2020-07-03
    • 2020-04-21
    • 2020-05-02
    相关资源
    最近更新 更多