临时包以在lookupy中发布模型支持
项目描述
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 作为值,则查找将始终失败,尽管在 Python 2 中 None < 2 == True。最好的办法是避免这种局面。
由于目前select的工作方式,如果与filter链式使用,应在其之后而不是之前调用(除非用于查找的键也正在被选择)。我计划在后续版本中修复此问题。
运行测试
$ make test
为了方便在所有环境中(Python 2.7和3.2)进行测试,请运行:
$ tox
待办事项
测量大数据集的性能
实现JSON文件的命令行界面
许可证
本库按现状提供,受MIT许可证约束。
项目详情
lookupy-unmanaged-0.4.tar.gz 的散列值
算法 | 散列摘要 | |
---|---|---|
SHA256 | e07a5afbe4d535de0cd099a40ecc3959ced87342f6c6ba41b3d933e636059450 |
|
MD5 | 17bf1020808185b99b6d01026f9a0e2b |
|
BLAKE2b-256 | c5de4bb6b57e9214df13ab95b55f6ef03150a3628200f84039f0b90665d672c7 |