Django:模型_QuerySet对象实例
QuerySet对象实例
前面几章学习了QuerySet对象的很多方法,在实际场景中可能需要几个不同的方法相互调用,才能实现最终的需求,特别是在根据多个表关系来查询数据时。所以要做到灵活的使用的话,还是需要多练习
模型类
后面会介绍几个实际例子,所有例子都是基于下面几个模型类来实现的
例1:
⑴模型类
⑵查看数据:学生表
⑶查看数据:老师表
⑷查看数据:课程表
⑸查看数据:成绩表
查询每科平均成绩大于60分的同学和其平均成绩
例2:使用自己的方法
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from polls.models import Student,Score,Course,Teacher
from django.db import models
from django.db import connection
def index(request):
#查询每科平均成绩大于60分的同学和其平均成绩
score_avgs = Student.objects.annotate(score_avg=(models.Avg("score__score")))#查询每个学生的平均成绩
print(score_avgs)
students_list = []
scores_avg_list = []
for students_avg in score_avgs:#对返回的QuerySet进行遍历:返回模型类
print(students_avg)
print(students_avg.score_avg)
if students_avg.score_avg >= 60:#依次判断每个模型类下面的score_avg属性值是否>=60
students_list.append(students_avg.name)#获取score_avg属性值是否>=60数据中的name属性值(因为是从Student模型类开始查询的,因此会返回Student表中的数据)
scores_avg_list.append(students_avg.score_avg)
else:
pass
student_score_dicts = dict(zip(students_list,scores_avg_list))#将两个列表打包并转换为字典
print(students_list)
print(student_score_dicts)
return HttpResponse("success")
"""
<QuerySet [<Student: Student object (1)>, <Student: Student object (2)>, <Student: Student object (3)>, <Student: Student object (4)>, <Student: Student object (5)>, <Student: Student object (6)>]>
Student object (1)
87.625
Student object (2)
74.5
Student object (3)
50.333333333333336
Student object (4)
74.0
Student object (5)
64.0
Student object (6)
44.0
['张三', '李四', '小红', '小张']
{'小红': 74.0, '张三': 87.625, '小张': 64.0, '李四': 74.5}
"""
例2_1:使用QuerySet方法
⑴编辑视图
⑵编辑模板
⑶访问
注:从上面例子可以看到
1、直接多次链式调用QuerySet方法(前提是前一个方法返回的是一个QuerySet对象),并合理的利用表关系以及过滤条件可以很方便的查询出我们想要的结果
2、上面例子对应的SQL语句为:
'SELECT `student`.`name`, AVG(`score`.`score`) AS `score_avg` FROM `student` LEFT OUTER JOIN `score` ON (`student`.`id` = `score`.`students_id`) GROUP BY `student`.`id` HAVING AVG(`score`.`score`) >= 60.0
3、我们也可以分析下上面例子中为什么要这么写查询语句:
⑴首先我们最终查询的是"同学"(目的数据在主表中),因此可以从Student模型类中查询:Student.objects
⑵学生的"平均成绩"是在成绩表Score模型类中体现的,因此查询条件需要从Score模型类开始:Student.objects.annotate(score_avg=(models.Avg("score__score")))。这步就可以查询出每个学生的平均成绩了
①反向查询:第一个score表示小写形式的Score模型类名,第二个score表示Score模型类中的关联字段(待查询的字段)
⑶步骤2中查询出了每个学生的平均成绩,且返回值为一个QuerySet对象,因此可以继续使用QuerySet对象方法filter()进行过滤
⑷通过步骤3就过滤出了"平均成绩大于60分的同学"的数据,此时就可以使用values()方法,将我们想要的结果提取出来
查询学生"张三"选了哪些课
例3:自己的方法
⑴编辑视图
注:
1、第一步中查询的是学生张三选了哪些课,此时查找到的是课程的id:学生选了哪些课是在成绩表Score模型类中体现了,学生是在学生表Student模型类中,两个表通过外键"students"进行关联。这里推荐使用正向查询(感觉比较好理解一点)
⑴首先确定最终查询的是"课程",且课程体现在成绩表Score模型类中的,因此建议在成绩表Score模型中进行查询:courses_1 = Score.objects
⑵过滤条件为学生姓名为张三,因此最后肯定是在Student表中进行过滤:name="张三"
⑶Score模型为子表,Student表为主表,两个表通过外键"students"进行关联,因此为正向查询:Score.objects.filter(students__name="张三")
2、在找到张三所选课的id后,就可以直接使用id来在课程表Course模型类中进行查询,课程的名字了
3、上面这种方法还可以进一步优化下:
courseNames = Course.objects.filter(id__in=[Student.objects.filter(name="张三").values("score__courses")]).values("name")
例3_1:多个表关系进行查询
⑴编辑视图
注:从上面例子可以看到
1、上面这种方法就直接利用了多个表关系来进行查询,使用这种方法的话,就显得很是简便了且比较高效
2、上面查询语句可以这么理解:
⑴首先,最终查询的是课程,因此从Course模型开始: Course.objects
⑵学生选了哪些课程是从分数表Score中体现的,因此filter方法后面从Score模型开始:Course.objects.filter(score),从Course模型到Score模型为反向查询,则使用Score模型名小写(此时就相当于查询到了Score模型了)
⑶Score模型又可以通过其模型中的外键"students"来关联到Student模型,从而根据学生名字进行过滤:Course.objects.filter(score__students__name="张三")。因为是根据学生name="张三"来进行过滤的,那么最后肯定会关联到Student模型类中的name字段(这里为正向查询)
⑷注:首先确定好从最终查询的数据在哪个模型表中,第二步确定最终的过滤条件在哪个模型表中,其次确定从哪个模型表中进行关联过滤,最后确定中间表的关联方式
3、SELECT `course`.`name` FROM `course` INNER JOIN `score` ON (`course`.`id` = `score`.`courses_id`) INNER JOIN `student` ON (`score`.`students_id` = `student`.`id`) WHERE `student`.`name` = '张三'
查询所有同学的id,姓名,选课的数量,总成绩
例4:
def index(request):
# 查询所有同学的id,姓名,选课的数量,总成绩
students = Student.objects.annotate(courses_num=models.Count("score__courses"),totle_score=models.Sum("score__score")).values("id","name","courses_num","totle_score")
for student in students:
print(student)
#这个只是单纯的查询选课的数量,总成绩
students = Student.objects.annotate(courses_num=models.Count("score__courses"),totle_score=models.Sum("score__score"))
print(students)
for student in students:
print(student)
print(student.id,student.name,student.courses_num,student.totle_score)
return HttpResponse("success")
"""
{'id': 1, 'name': '张三', 'totle_score': 350.5, 'courses_num': 4}
{'id': 2, 'name': '李四', 'totle_score': 223.5, 'courses_num': 3}
{'id': 3, 'name': '王五', 'totle_score': 151.0, 'courses_num': 3}
{'id': 4, 'name': '小红', 'totle_score': 74.0, 'courses_num': 1}
{'id': 5, 'name': '小张', 'totle_score': 64.0, 'courses_num': 1}
{'id': 6, 'name': '张伟', 'totle_score': 44.0, 'courses_num': 1}
<QuerySet [<Student: Student object (1)>, <Student: Student object (2)>, <Student: Student object (3)>, <Student: Student object (4)>, <Student: Student object (5)>, <Student: Student object (6)>]>
Student object (1)
1 张三 4 350.5
Student object (2)
2 李四 3 223.5
Student object (3)
3 王五 3 151.0
Student object (4)
4 小红 1 74.0
Student object (5)
5 小张 1 64.0
Student object (6)
6 张伟 1 44.0
"""
查询姓"李"的老师的个数
例5:
⑴编辑视图
查询没有学过李老师的课程的学生的id和姓名
例6:
⑴编辑视图
注:
1、要查询没有选过李老师课程的学生,可以返过来先找到学过李老师课程的学生
2、最终要查询的是学生,因此从Student开始:Student.objects
2.1、最终的过滤条件是老师表Teacher模型类中的name="李老师",所以最后肯定需要关联到Teacher模型类
3、学生选过哪些课,是在成绩表Score中体现的,因此过滤表从Score模型开始:filter(score)。Student模型类到Score模型为反向查询,此时就相当于是找到了成绩表Score模型类了
4、学生选的课在成绩表Score中是通过courses字段体现的,因此关联courses字段:filter(score__courses),正向查询
5、步骤4就相当于找到了课程模型Course(课程表),课程表又是通过模型中的teachers字段关联老师表的Teacher,因此继续关联:filter(score__courses__teachers),正向查询
6、最后通过老师表中的:teachers__name__endswith="李"来找到李老师
例6_1:
⑴编辑视图
总结
1、第一步,确定好,最终查询的是哪个模型中的数据,是哪个模型就从哪个模型开始:xxx.objects
2、第二步,确定好从哪个模型开始过滤数据(此时也需要确定好是正向查询还是反向查询)
3、第三步确定最后一个关联表(字段),即最终是在哪个表中进行过滤的,根据什么条件进行过滤
4、第四步确定中间的关联表或字段(正向查询还是反向查询)