跳转到主要内容

Django QuerySet 启发式的查询字典列表的接口

项目描述

Lookupy是一个Python库,它提供了一种类似于Django QuerySet的接口,用于查询(筛选和选择)数据(字典列表)。

它最初是一个用于解析和从HAR(HTTP存档)文件中提取有用数据的库,但在过程中我意识到,一个通用库可能很有用,因为我经常需要从例如来自Facebook或GitHub API的JSON集合中获取数据。我选择模仿Django queryset API,因为我熟悉它。

我不总是使用这个库,但当我与深度嵌套的json/dicts(例如Facebook,GitHub等API返回的那种)一起工作时,我会发现它很有帮助。对于日常事务,我更喜欢Python内置的功能结构,如map,filter,列表推导式。

需求

  • Python [已测试2.7和3.2]

  • nose [可选,用于运行测试]

  • coverage.py [可选,用于测试覆盖率]

  • Tox [可选,用于在Python的不同版本上构建和测试]

安装

安装此库的最简单方法是使用pip

$ pip install lookupy
提示! 考虑在

virtualenv

快速入门

由于此库基于Django QuerySets,因此首先了解它们的工作原理会有所帮助。在Django中,QuerySets用于构建SQL查询以从数据库中检索数据。使用QuerySet对象的filter方法相当于编写SQL中的WHERE子句。

将相同的概念应用于简单的数据集合(字典列表),Lookupy可以使用所谓的“查找参数”指定的某些条件来提取数据子集。

但是首先,我们需要根据以下方式从数据集中构建一个Collection对象:

>>> from lookupy import Collection, Q
>>> data = [{'framework': 'Django', 'language': 'Python', 'type': 'full-stack'},
...         {'framework': 'Flask', 'language': 'Python', 'type': 'micro'},
...         {'framework': 'Rails', 'language': 'Ruby', 'type': 'full-stack'},
...         {'framework': 'Sinatra', 'language': 'Ruby', 'type': 'micro'},
...         {'framework': 'Zend', 'language': 'PHP', 'type': 'full-stack'},
...         {'framework': 'Slim', 'language': 'PHP', 'type': 'micro'}]
>>> c = Collection(data)

为了从集合中过滤出一些数据,我们调用filter方法,并将我们的查找参数传递给它。

>>> c.filter(framework__startswith='S')
<lookupy.lookupy.QuerySet object at 0xb740d40c>

>>> list(c.filter(framework__startswith='S'))
[{'framework': 'Sinatra', 'type': 'micro', 'language': 'Ruby'},
{'framework': 'Slim', 'type': 'micro', 'language': 'PHP'}]

查找参数基本上像是一个条件语句,形式为<key>__<lookuptype>=<value>,其中<key>是字典中的一个键,<lookuptype>是预定义的关键字之一,用于指定如何将<value>与字典中每个键对应的实际值匹配。请参见查找类型列表

作为参数传递的多个查找默认使用and逻辑运算符(稍后我们将看到ornot也支持)组合。

>>> list(c.filter(framework__startswith='S', language__exact='Ruby'))
[{'framework': 'Sinatra', 'type': 'micro', 'language': 'Ruby'}]

对于ornot,我们可以使用Q对象来组合复杂的查找,并将它们作为位置参数传递,同时将查找参数作为关键字参数传递。不出所料,位运算符&(与)、|(或)和~(非)被重写为分别作为逻辑andornot操作(就像在Django中那样工作)。

>>> list(c.filter(Q(language__exact='Python') | Q(language__exact='Ruby')))
[{'framework': 'Django', 'language': 'Python', 'type': 'full-stack'},
 {'framework': 'Flask', 'language': 'Python', 'type': 'micro'},
 {'framework': 'Rails', 'language': 'Ruby', 'type': 'full-stack'},
 {'framework': 'Sinatra', 'language': 'Ruby', 'type': 'micro'}]
>>> list(c.filter(~Q(language__startswith='R'), framework__endswith='go'))
[{'framework': 'Django', 'language': 'Python', 'type': 'full-stack'}]

Lookupy还支持通过在QuerySet对象上提供select方法来使结果仅包含所选字段。

在QuerySet上调用filter或select方法返回另一个QuerySet,因此这些调用可以链接在一起。内部,过滤和选择利用Python的生成器进行懒加载评估。此外,QuerySetCollection都实现了迭代器协议,因此在消耗之前不会进行任何评估。

>>> result = c.filter(Q(language__exact='Python') | Q(language__exact='Ruby')) \
              .filter(framework__istartswith='s')) \
              .select('framework')
>>> for item in result: # <-- this is where filtering will happen
...     print(item)
...
[{'framework': 'Sinatra'}]

对于嵌套字典,查找参数中的键可以使用双下划线构建,例如request__status__exact=404。最后,也可以使用相同的Q对象通过嵌套键值对集合过滤数据。

>>> data = [{'a': 'python', 'b': {'p': 1, 'q': 2}, 'c': [{'name': 'version', 'value': '3.4'}, {'name': 'author', 'value': 'Guido van Rossum'}]},
...         {'a': 'erlang', 'b': {'p': 3, 'q': 4}, 'c': [{'name': 'version', 'value': 'R16B01'}, {'name': 'author', 'y': 'Joe Armstrong'}]}]
>>> c = Collection(data)
>>> list(c.filter(b__q__gte=4))
[{'a': 'erlang', 'c': [{'name': 'version', 'value': 'R16B01'}, {'y': 'Joe Armstrong', 'name': 'author'}], 'b': {'q': 4, 'p': 3}}]
>>> list(c.filter(c__filter=Q(name='version', value__contains='.')))
[{'a': 'python', 'c': [{'name': 'version', 'value': '3.4'}, {'name': 'author', 'value': 'Guido van Rossum'}], 'b': {'q': 2, 'p': 1}}]

在上一个示例中,我们使用Q对象通过嵌套键值对集合过滤原始字典,即我们查询仅包含包含点(.)的版本字符串的语言。请注意,这与过滤嵌套集合本身不同。为此,我们可以轻松地为子集合构建Collection对象。

请参阅examples子目录以获取更多使用示例。

支持的查找类型

以下是当前支持的查找类型:

  • exact 精确相等(默认)

  • neq 不相等

  • contains 包含

  • icontains 不区分大小写的包含

  • in 成员

  • startswith 字符串开头匹配

  • istartswith 不区分大小写的开头匹配

  • endswith 字符串结尾匹配

  • iendswith 不区分大小写的结尾匹配

  • gt 大于

  • gte 大于等于

  • lt 小于

  • lte 小于等于

  • regex 正则表达式搜索

  • filter 嵌套过滤

注意事项!

  1. 如果将不存在的key传递给select,则它将在所有结果中包含值为None的结果。

  2. 如果将不存在的key传递给filter,则查找将始终失败。起初,这似乎与第一点不一致,但这样做是为了保持整体行为可预测。例如,如果使用整数lt查找与不存在的键,比如2作为值,那么查找将始终失败,即使None < 2 == True在Python 2中。最好是避免这种情况。

  3. 由于当前select的工作方式,如果与filter链接,则应该仅在它之后调用它,而不是在它之前(除非用于查找的键也被选中)。我计划在以后的版本中修复这个问题。

运行测试

$ make test

要方便地在所有环境中(Python 2.7和3.2)进行测试,请运行:

$ tox

待办事项

  • 测量大型数据集的性能

  • 实现JSON文件的CLI

许可证

本库按原样提供,受MIT许可证保护。

项目详细信息


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

Lookupy-0.2.tar.gz (10.0 kB 查看哈希值)

上传时间 源代码

由以下机构支持