就目前了解到的,Django的ORM操作还是比较适用于单表查询,多表关联查询更多是要依赖于外键,否则势必增加查询复杂度。 接下来就为各位奉上进阶版查询三件套:extra,aggregate,annotate。所有案例均是以postgresql对象作为参照。 案例模型:
class Student(models.Model):
id = models.AutoField
student_name = models.CharField(max_length=100,unique=True)
age= models.IntegerField(default = 0)
delete_status = models.IntegerField(default = 0)
register_time = models.DateTimeField(auto_now_add=True)
extra
格式规范:
extra(select=None, where=None, params=None,
tables=None, order_by=None, select_params=None)
顾名思义,额外的意思,该方法主要用于在查询结果中做额外的处理,如果这么说不好理解的话,下面奉上案例:
查询结果增加字段
1、增加常量字段
Student.objects.all().extra(select={'math_score': 98})
在表Student的查询结果增加字段math_score,每一行值均为98。其效果等同于:
select a.*,98 as math_score from app_student a;
2、增加已有字段的变种
更确切的说增加的字段可以是基于已有字段经过一系列简单或复杂的操作之后,新生成一个字段,该字段内容依赖于已有字段。比如常见的分组统计。
Student.objects.all().extra(select={'register_time':"to_char(register_time,'mmdd')"}).values("register_time").annotate(count=Count("register_time")).order_by('-register_time')[:5].values_list('count', flat=True)
为了一步到位,这边直接整复杂的查询,其效果等同于:
select to_char(register_time,'mmdd') as register_time,count(*) from app_student group by to_char(register_time,'mmdd') order by to_char(register_time,'mmdd') desc;
其目的就是为了统计每一天学生注册人数,并且按注册时间倒序排列。在这个案例中,extra是负责对register_time转指定格式的字符以方便统计,values指定按哪个字段统计,也就是group by后跟的字段,annotate为统计方法,这里使用的是Count,最后order_by为降序排列。
3、增加字段为其他表的内容或统计值
Student.objects.all().extra(select={'random_cnt':"select count(*) from app_another_table "})
这里关联表就随便取了一张没有任何含义的表,其效果等同于:
select a.*,(select count(*) from app_another_table) from app_student a;
where和table参数的使用
Student.objects.all().extra(table=['app_another_table'], where=['another_id= id'])
其效果等同于:
select a.*,b.* from app_student a left join app_another_table b on a.id=b.another_id;
aggregate
翻译过来是总数、合计的意思,所以她的作用显而易见,直接上案例:
Student.objects.aggregate(Avg('age‘), Max('age‘), Min('age‘))
其效果等同于:
select avg('age‘), max('age‘), min('age‘) from app_student;
其目的是为了统计学生的平均年龄以及最大和最小年龄。
annotate
相比较于前两个,annotate的实际功用和命名就有点风牛马不相及了。其作用主要是分组(group by),举例如下: 示例一:
Student.objects.annotate(Count(*))
其效果等同于:
select id,count(*) from app_student group by id;
示例二:
Student.objects.values('student_name').annotate(Count(*))
其效果等同于:
select student_name,count(*) fromo app_student group by student_name;
这三个方法的组合技在介绍extra的时候基本放过了,愿在知识的海洋里,我们共同找寻方向。
|