|
|
@@ -169,9 +169,9 @@ LOGGING = {
|
|
|
|
|
|
4. 在配置好Django-Debug-Toolbar之后,页面右侧会看到一个调试工具栏,如下图所示,上面包括了如前所述的各种调试信息,包括执行时间、项目设置、请求头、SQL、静态资源、模板、缓存、信号等,查看起来非常的方便。
|
|
|
|
|
|
- 
|
|
|
+ 
|
|
|
|
|
|
-#### 优化ORM代码
|
|
|
+### 优化ORM代码
|
|
|
|
|
|
在配置了日志或Django-Debug-Toolbar之后,我们可以查看一下之前将老师数据导出成Excel报表的视图函数执行情况,这里我们关注的是ORM框架生成的SQL查询到底是什么样子的,相信这里的结果会让你感到有一些意外。执行`Teacher.objects.all()`之后我们可以注意到,在控制台看到的或者通过Django-Debug-Toolbar输出的SQL是下面这样的:
|
|
|
|
|
|
@@ -185,7 +185,7 @@ SELECT `tb_subject`.`no`, `tb_subject`.`name`, `tb_subject`.`intro`, `tb_subject
|
|
|
SELECT `tb_subject`.`no`, `tb_subject`.`name`, `tb_subject`.`intro`, `tb_subject`.`create_date`, `tb_subject`.`is_hot` FROM `tb_subject` WHERE `tb_subject`.`no` = 103; args=(103,)
|
|
|
```
|
|
|
|
|
|
-这里的问题通常被称为“1+N查询”(或“N+1查询”),原本获取老师的数据只需要一条SQL,但是由于老师关联了学科,当我们查询到N条老师的数据时,Django的ORM框架又向数据库发出了N条SQL去查询老师所属学科的信息。每条SQL执行都会有较大的开销而且会给数据库服务器带来压力,如果能够在一条SQL中完成老师和学科的查询肯定是更好的做法,这一点也很容易做到,相信大家已经想到怎么做了。是的,我们可以使用连接查询,但是在使用Django的ORM框架时如何做到这一点呢?对于多对一关联(如投票应用中的老师和学科),我们可以使用`QuerySet`的用`select_related()`方法来加载关联对象;而对于多对多关联(如电商网站中的订单和商品),我们可以使用`prefetch_related()`方法来加载关联对象。
|
|
|
+这里的问题通常被称为“1+N查询”(有的地方也将其称之为“N+1查询”),原本获取老师的数据只需要一条SQL,但是由于老师关联了学科,当我们查询到`N`条老师的数据时,Django的ORM框架又向数据库发出了`N`条SQL去查询老师所属学科的信息。每条SQL执行都会有较大的开销而且会给数据库服务器带来压力,如果能够在一条SQL中完成老师和学科的查询肯定是更好的做法,这一点也很容易做到,相信大家已经想到怎么做了。是的,我们可以使用连接查询,但是在使用Django的ORM框架时如何做到这一点呢?对于多对一关联(如投票应用中的老师和学科),我们可以使用`QuerySet`的用`select_related()`方法来加载关联对象;而对于多对多关联(如电商网站中的订单和商品),我们可以使用`prefetch_related()`方法来加载关联对象。
|
|
|
|
|
|
在导出老师Excel报表的视图函数中,我们可以按照下面的方式优化代码。
|
|
|
|
|
|
@@ -202,15 +202,13 @@ queryset = Teacher.objects.all().only('name', 'good_count', 'bad_count')
|
|
|
当然,如果要统计出每个学科的老师好评和差评的平均数,利用Django的ORM框架也能够做到,代码如下所示:
|
|
|
|
|
|
```Python
|
|
|
-queryset = Teacher.objects.values('subject').annotate(
|
|
|
- good=Avg('good_count'), bad=Avg('bad_count'))
|
|
|
+queryset = Teacher.objects.values('subject').annotate(good=Avg('good_count'), bad=Avg('bad_count'))
|
|
|
```
|
|
|
|
|
|
这里获得的`QuerySet`中的元素是字典对象,每个字典中有三组键值对,分别是代表学科编号的`subject`、代表好评数的`good`和代表差评数的`bad`。如果想要获得学科的名称而不是编号,可以按照如下所示的方式调整代码:
|
|
|
|
|
|
```Python
|
|
|
-queryset = Teacher.objects.values('subject__name').annotate(
|
|
|
- good=Avg('good_count'), bad=Avg('bad_count'))
|
|
|
+queryset = Teacher.objects.values('subject__name').annotate(good=Avg('good_count'), bad=Avg('bad_count'))
|
|
|
```
|
|
|
|
|
|
可见,Django的ORM框架允许我们用面向对象的方式完成关系数据库中的分组和聚合查询。
|