Django ORM返回QuerySets的某些函数

整个Django框架,如果要问喜欢那部分,我首先想到的就是它的ORM;Django集成的ORM好用,秉承了Pythonic的理念,还有很浓的OO味道。单个看ORM的函数,似乎是管中窥豹,如果你把各种函数组合起来写,你会发现,原来也可以这么用的,太酷了吧?但还是单独看看这些函数的,等你逐个了解了,一气呵成的感觉就有了。

拾遗,随意拿些函数来说说,读者只需了解,理念就形成了,有兴趣的稍微记忆下,就是自己的东西了。

1.annotate
说到annotate,不能提到聚合aggregate(Avg,Count,Max,Min...),因为annotate需要结合这些聚合函数,才能发挥它的作用,比如博客应用,博客和博客的回复Commnet,取出博客列表的同时,你如果也要取出回复的条数,应该怎么写呢:
blogs = Blog.objects.annotate(Count('commnet'))

这回取出博客列表的同时,也能取到相应的回复条数了。template中怎么取值:
{%for blog in blogs%}
{{blog.comment__count}}
{%endfor%}

你也可以该字段给个别名:
blogs = Blog.objects.annotate(comment_count=Count('commnet'))

这个函数,如果结合filter exclude get,出来的效果你懂的!

2 values
values是返回QuerySet吗?严格说是ValuesQuerySet,是QuerySet的子集。看代码:
Blog.objects.values()

得出的是:
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'},...]
没有指定参数,默认会返回全部的字段字典列表。指定参数:
Blog.objects.values('id', 'name')
得出:
[{'id': 1, 'name': 'Beatles Blog'}]
在template里使用它 只需把它当成一个iterable,循环取值即可,每条记录就是一个字典,记录的属性就是实体的属性字段。
值得注意的是它返回的是ValuesQuerySet,而不是QuerySet,如果你使用了values()后,再使用QuerySet的函数如filter,出现什么问题,你可以试试。

3 dates
顾名思义,dates是和时间有关的函数,用法:
Entry.objects.dates('pub_date', 'year')

结果:

[datetime.datetime(2005, 1, 1),...]

得出的是时间datetime列表,和values函数相似,得出的是QuerySet的子集:DateQuerySet;这个函数不好理解,如上面的Entry.objects.dates('pub_date', 'year'),是什么意思呢?
其实就是取出所有博客的时间列表,参数‘year’,出来的时间列表 是以年份为依据,不会有重复年份,月份和日期默认是1;比如众多blog中,有几万条,发表时间当然不止同一年的,该语句出来 :
[datetime.datetime(2005, 1, 1),datetime.datetime(2006, 1, 1),datetime.datetime(2007, 1, 1),datetime.datetime(2008, 1, 1),...]
嗯,时间列表,在template用,你应该知道了!

参数 field kind order,形如:
Entry.objects.dates('pub_date', 'day', order='DESC')
field就是实体的一个时间字段,kid就是 year month day,order就是排序 desc asc,好理解吧?

如果你还有疑问:我们想取出博客的所有月份,怎么写? 呃,试试这样:

Blog.objects.dates('pub_date', 'month', order='DESC')...

结果:

[datetime.datetime(2005, 1, 1),datetime.datetime(2005, 2, 1),... ,datetime.datetime(2006, 4, 1),...,datetime.datetime(2008, 6, 1),...]

但如果想取所有日期列表呢?唉,有必要吗?dates用途,你平时见到的归档 都是按照年份或者月份归档的,如果按照日期归档,该网站的文摘更新速度不是一般的快哦!还是有办法的:
Blog.objects.dates('pub_date', 'day', order='DESC')...

4 defer
defer是个好函数,有时候一个实体有过多的字段,取实体或者实体列表的时候,占用了多大的内存,而你却不需要取出全部的字段,比如博客的正文内容,你不需要立即检索数据库,这时defer就是你需要的东西。defer函数与前面讲的values有区别的,前者返回的是ValuesQuerySet,而defer返回的是QuerySet对象,这意味着,使用了defer后,你还可以结合QuerySet其他的函数,让整个语句结合更多的条件;Django的ORM除了做得OO,还很注重性能的。
如果取博客的文章列表,让容量很大的正文和副标题在数据库层不进行检索,看看代码:
Blog.objects.defer("content", "subtitle")

defer的用法还比较多,比如:
my_queryset=Blog.objects.select_related().defer("commnet__content", "commnet__pic")

以上的语句说明,获取博客表和回复表,他们两表是使用了内连接,获取的时候,让回复表不检索回复内容和图片。select_related之前记得有说过,是一次性表关联。

如果你想再原来语句获取到的实体列表上取消某些字段的延时,可以通过这样的用法取消延时,让数据库立即检索全部字段:
my_queryset.defer(None)

还有很多的defer组合用法,需要自己去慢慢体会了。

5 only
only很多程度上和defer是同一类的东西,可以理解为defer的相反函数吧。比如Person实体里有三个字段:name age birthday,下面这两条语句是等价的:

Person.objects.defer("age", "biography")
Person.objects.only("name")

posted @ 2018-08-22 14:40  yugb  阅读(637)  评论(0编辑  收藏  举报