一个对象,它使多个可迭代对象能够以查询集兼容的方式懒加载。
项目描述
本模块提供了一种将多个有限可迭代对象链接起来,以便作为查询集兼容对象消费的方法。
快速入门
让我们从一个例子开始。假设我们有一些抽象数据库模型,我们可以稍后重用这些字段
class Titled(db.Model): title = db.CharField(max_length=100) class Meta: abstract = True class Dynamic(db.Model): duration = db.PositiveIntegerField() class Meta: abstract = True
我们还拥有一些具有这些字段之一的具体数据库模型
class Video(Titled, Dynamic): RESOLUTION = ( (1, '240p'), (2, '320p'), (3, '480p'), (4, '720p'), (5, '1080p') ) author = db.CharField(max_length=100) resolution = db.IntegerField(choices=RESOLUTION) class Song(Titled, Dynamic): GENRE = ( (1, 'Country'), (2, 'Folk'), (3, 'Polka'), (4, 'Western'), (5, 'World') ) artist = db.CharField(max_length=100) genre = db.IntegerField(choices=GENRE)
我们的数据库已经包含了一些数据
>>> Video.objects.all() [<Video: Psy - Gangnam Style (253 s at 1080p)>, <Video: Justin Bieber - Baby (225 s at 720p)>, <Video: Lady Gaga - Bad Romance (308 s at 320p)>, <Video: Shakira - Waka Waka (211 s at 480p)>] >>> Song.objects.all() [<Song: Gotye feat. Kimbra - Somebody That I Used to Know (244 s; Folk)>, <Song: Coldplay - Clocks (307 s; Polka)>, <Song: Muse - Madness (279 s; Country)>, <Song: Florence + The Machine - Spectrum (218 s; Folk)>]
基本链
让我们创建一个简单的链
>>> from dj.chain import chain >>> media = chain(Video.objects.all(), Song.objects.all())
我们可以对其调用相关的查询集方法
>>> media.count() 8
我们还可以进一步过滤它
>>> list(media.filter(duration__gt=250)) [<Video: Psy - Gangnam Style (253 s at 1080p)>, <Video: Lady Gaga - Bad Romance (308 s at 320p)>, <Song: Coldplay - Clocks (307 s; Polka)>, <Song: Muse - Madness (279 s; Country)>]
检查累积长度
>>> media.filter(duration__gt=250).count() 4
使用索引和切片
>>> media.filter(duration__gt=250)[1] <Video: Lady Gaga - Bad Romance (308 s at 320p)> >>> list(media[3:6]) [<Video: Shakira - Waka Waka (211 s at 480p)>, <Song: Gotye feat. Kimbra - Somebody That I Used to Know (244 s; Folk)>, <Song: Coldplay - Clocks (307 s; Polka)>] >>> list(media[1::3]) [<Video: Justin Bieber - Baby (225 s at 720p)>, <Song: Gotye feat. Kimbra - Somebody That I Used to Know (244 s; Folk)>, <Song: Florence + The Machine - Spectrum (218 s; Folk)>]
使用累积排序和过滤
>>> list(media.order_by('title')) [<Video: Justin Bieber - Baby (225 s at 720p)>, <Video: Lady Gaga - Bad Romance (308 s at 320p)>, <Song: Coldplay - Clocks (307 s; Polka)>, <Video: Psy - Gangnam Style (253 s at 1080p)>, <Song: Muse - Madness (279 s; Country)>, <Song: Gotye feat. Kimbra - Somebody That I Used to Know (244 s; Folk)>, <Song: Florence + The Machine - Spectrum (218 s; Folk)>, <Video: Shakira - Waka Waka (211 s at 480p)>] >>> list(media.order_by('-duration').filter(duration__lt=300)) [<Song: Muse - Madness (279 s; Country)>, <Video: Psy - Gangnam Style (253 s at 1080p)>, <Song: Gotye feat. Kimbra - Somebody That I Used to Know (244 s; Folk)>, <Video: Justin Bieber - Baby (225 s at 720p)>, <Song: Florence + The Machine - Spectrum (218 s; Folk)>, <Video: Shakira - Waka Waka (211 s at 480p)>]
等等。
链异构可迭代对象
我们可以将不是查询集的可迭代对象添加到集合中
>>> from collections import namedtuple >>> Book = namedtuple('Book', "author title page_count") >>> books=( ... Book(author='Charles Dickens', title='A Tale of Two Cities', page_count=869), ... Book(author='Miguel de Cervantes', title='Don Quixote', page_count=1212), ... ) >>> media=chain(Video.objects.all(), books) >>> media.count() 6 >>> list(media) [<Video: Psy - Gangnam Style (253 s at 1080p)>, <Video: Justin Bieber - Baby (225 s at 720p)>, <Video: Lady Gaga - Bad Romance (308 s at 320p)>, <Video: Shakira - Waka Waka (211 s at 480p)>, Book(author='Charles Dickens', title='A Tale of Two Cities', page_count=869), Book(author='Miguel de Cervantes', title='Don Quixote', page_count=1212)]
在这种情况下,您也可以使用累积排序。您需要注意的唯一一点是,为了使累积结果按正确顺序排序,非查询集的可迭代对象应该预先排序。示例
>>> list(media.order_by('title')) [Book(author='Charles Dickens', title='A Tale of Two Cities', page_count=869), <Video: Justin Bieber - Baby (225 s at 720p)>, <Video: Lady Gaga - Bad Romance (308 s at 320p)>, Book(author='Miguel de Cervantes', title='Don Quixote', page_count=1212), <Video: Psy - Gangnam Style (253 s at 1080p)>, <Video: Shakira - Waka Waka (211 s at 480p)>]
您还可以使用累积的 values 和 values_list 转换
>>> media = chain(mt.Video.objects.all(), mt.books) >>> list(media.values('title')) [{'title': u'Gangnam Style'}, {'title': u'Baby'}, {'title': u'Bad Romance'}, {'title': u'Waka Waka'}, {'title': u'A Tale of Two Cities'}, {'title': u'Don Quixote'}] >>> list(media.values_list('title', 'author')) [(u'Gangnam Style', u'Psy'), (u'Baby', u'Justin Bieber'), (u'Bad Romance', u'Lady Gaga'), (u'Waka Waka', u'Shakira'), (u'A Tale of Two Cities', u'Charles Dickens'), (u'Don Quixote', u'Miguel de Cervantes')] >>> list(media.values_list('author', flat=True)) [u'Psy', u'Justin Bieber', u'Lady Gaga', u'Shakira', u'Charles Dickens', u'Miguel de Cervantes']
自定义过滤、排序和转换
链提供在产生值时使用的特殊可覆盖的静态方法
xfilter(value) - 仅当 xfilter(value) 返回 True 时产生值。请参阅下面的已知问题。
xform(value) - 在产生值之前即时转换值。它仅对指定切片内的值和通过 xfilter 的值进行调用。
xkey(value) - 如果使用排序,则返回用于元素间比较的值。为了正确排序完整结果,单个可迭代对象应预先排序。任何累积的 order_by 子句都在使用 xkey 方法之前执行。
在不兼容的可迭代对象上静默忽略方法
链可以包含类似查询集的对象和其他可迭代对象。如果链对象上集体调用,则有一些仅适用于前者的方法。这些是
defer
exclude
extra
filter
only
prefetch_related
select_for_update
select_related
using
默认情况下,dj.chain 将任何具有集体调用所需方法的可迭代对象视为类似查询集的对象。例如,如果您的自定义可迭代对象支持 defer 方法,它将在集体 defer 调用中使用。如果这种行为不受欢迎,您应在构建链时传递 strict=True
c = chain(Article.objects.all(), custom_entries, strict=True)
在这种情况下,上述方法仅在实际查询集实例上调用。请注意,具有自定义其他可迭代对象处理方法(如 count 和 order_by)的方法仍然有效。
不支持的方法
以下方法在异构环境中无法支持
create
get_or_create
bulk_create
以下方法目前尚不支持,但计划在未来的版本中支持
aggregate
annotate
dates
delete
distinct
get
in_bulk
reverse
update
已知问题
如果使用切片或 xfilter,则通过迭代所有可迭代对象来计算报告的 len(),因此性能较弱。请注意,len() 在将链转换为列表或在使用 Django 模板遍历链时用作 list()。如果这不是预期的,您可以使用如下方法将链转换为列表
list(e for e in some_chain)
链上的索引使用迭代,因此性能较弱。此功能仅作为最后的手段提供。另一方面,切片是惰性的。
集体 filter 和 exclude 静默跳过在不兼容的可迭代对象上的过滤。请使用 xfilter(value) 作为解决方案。
如何运行测试?
最简单的方法是运行
$ DJANGO_SETTINGS_MODULE="dj._chaintestproject.settings" django-admin.py test
变更日志
0.9.2
久违的 Python 3 支持(视为实验性)
0.9.1
支持集体 values 和 values_list 转换
支持集体 defer、extra、only、prefetch_related、select_for_update、select_related 和 using 方法(对于不兼容的可迭代对象静默忽略)
严格模式(非查询集对象不尝试与集体方法兼容)
修复了由于与 lck.django 不完全分离导致的导入错误。
0.9.0
代码已从 lck.django 分离。
支持使用类似 QuerySet 的链式 order_by 进行批量排序。
修复了具有自定义步长的切片问题。
所有源代码都已遵循PEP8规范。
项目详情
dj.chain-0.9.2.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | b52b0820b7939fef4e4f3b2132a40b934149d9433badba8a69acc5f7c46ee47b |
|
MD5 | 539230aa498f8d987cc6112c5684bb26 |
|
BLAKE2b-256 | 52edd534fa81cb6c9d0b24d933f2c062dbf694045f628de30ee689266e95755e |