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
- 提示! 考虑在
快速入门
由于此库基于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逻辑运算符(稍后我们将看到or和not也支持)组合。
>>> list(c.filter(framework__startswith='S', language__exact='Ruby'))
[{'framework': 'Sinatra', 'type': 'micro', 'language': 'Ruby'}]
对于or和not,我们可以使用Q对象来组合复杂的查找,并将它们作为位置参数传递,同时将查找参数作为关键字参数传递。不出所料,位运算符&(与)、|(或)和~(非)被重写为分别作为逻辑and、or和not操作(就像在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的生成器进行懒加载评估。此外,QuerySet和Collection都实现了迭代器协议,因此在消耗之前不会进行任何评估。
>>> 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 嵌套过滤
注意事项!
如果将不存在的key传递给select,则它将在所有结果中包含值为None的结果。
如果将不存在的key传递给filter,则查找将始终失败。起初,这似乎与第一点不一致,但这样做是为了保持整体行为可预测。例如,如果使用整数lt查找与不存在的键,比如2作为值,那么查找将始终失败,即使None < 2 == True在Python 2中。最好是避免这种情况。
由于当前select的工作方式,如果与filter链接,则应该仅在它之后调用它,而不是在它之前(除非用于查找的键也被选中)。我计划在以后的版本中修复这个问题。
运行测试
$ make test
要方便地在所有环境中(Python 2.7和3.2)进行测试,请运行:
$ tox
待办事项
测量大型数据集的性能
实现JSON文件的CLI
许可证
本库按原样提供,受MIT许可证保护。
项目详细信息
Lookupy-0.2.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 04406d54bea664d04f1cc3988e7f4966469ffedc826ae0d1543cd3ac7f3a90a0 |
|
MD5 | 2ce41b5c85f4e74bdbb48c70d14dfdda |
|
BLAKE2b-256 | 90bc1fc5fdb7943c0e10300e87b71e3494b9669c9682f340231822889e4ea044 |