From 208cd3eef5acfd349a17c3194e2d0fe326cfb66b Mon Sep 17 00:00:00 2001 From: jackfrued Date: Tue, 18 Jun 2019 23:37:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86Django=E9=83=A8?= =?UTF-8?q?=E5=88=86=E7=9A=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...50\345\222\214\346\227\245\345\277\227.md" | 127 +++++++++++++++++- ...66\347\232\204\345\272\224\347\224\250.md" | 8 +- Day41-55/res/echarts_bar_graph.png | Bin 0 -> 53301 bytes ...00\345\217\221\351\241\271\347\233\256.md" | 2 +- ...64\346\226\260\346\227\245\345\277\227.md" | 7 + 5 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 Day41-55/res/echarts_bar_graph.png create mode 100644 "\346\233\264\346\226\260\346\227\245\345\277\227.md" diff --git "a/Day41-55/46.\346\212\245\350\241\250\345\222\214\346\227\245\345\277\227.md" "b/Day41-55/46.\346\212\245\350\241\250\345\222\214\346\227\245\345\277\227.md" index 30e698303..bf25ab2f5 100644 --- "a/Day41-55/46.\346\212\245\350\241\250\345\222\214\346\227\245\345\277\227.md" +++ "b/Day41-55/46.\346\212\245\350\241\250\345\222\214\346\227\245\345\277\227.md" @@ -54,7 +54,88 @@ urlpatterns = [ ### 生成前端统计图表 +如果项目中需要生成前端统计图表,可以使用百度的[ECharts]()。具体的做法是后端通过提供数据接口返回统计图表所需的数据,前端使用ECharts来渲染出柱状图、折线图、饼图、散点图等图表。例如我们要生成一个统计所有老师好评数和差评数的报表,可以按照下面的方式来做。 +```Python +def get_teachers_data(request): + # 查询所有老师的信息(注意:这个地方稍后也需要优化) + queryset = Teacher.objects.all() + # 用生成式将老师的名字放在一个列表中 + names = [teacher.name for teacher in queryset] + # 用生成式将老师的好评数放在一个列表中 + good = [teacher.good_count for teacher in queryset] + # 用生成式将老师的差评数放在一个列表中 + bad = [teacher.bad_count for teacher in queryset] + # 返回JSON格式的数据 + return JsonResponse({'names': names, 'good': good, 'bad': bad}) +``` + +映射URL。 + +```Python +urlpatterns = [ + # 此处省略上面的代码 + path('teachers_data/', views.export_teachers_excel), + # 此处省略下面的代码 +] +``` + +使用ECharts生成柱状图。 + +```HTML + + + + + 老师评价统计 + + +
+

+ 返回首页 +

+ + + + +``` + +运行效果如下图所示。 + +![](./res/echarts_bar_graph.png) ### 配置日志 @@ -223,4 +304,48 @@ Django-Debug-Toolbar是项目开发阶段辅助调试和优化的神器,只要 urlpatterns.insert(0, path('__debug__/', include(debug_toolbar.urls))) ``` -4. 使用 - 如下图所示,在配置好Django-Debug-Toolbar之后,页面右侧会看到一个调试工具栏,上面包括了如前所述的各种调试信息,包括执行时间、项目设置、请求头、SQL、静态资源、模板、缓存、信号等,查看起来非常的方便。 \ No newline at end of file +4. 使用 - 如下图所示,在配置好Django-Debug-Toolbar之后,页面右侧会看到一个调试工具栏,上面包括了如前所述的各种调试信息,包括执行时间、项目设置、请求头、SQL、静态资源、模板、缓存、信号等,查看起来非常的方便。 + +### 优化ORM代码 + +在配置了日志或Django-Debug-Toolbar之后,我们可以查看一下之前将老师数据导出成Excel报表的视图函数执行情况,这里我们关注的是ORM框架生成的SQL查询到底是什么样子的,相信这里的结果会让你感到有一些意外。执行`Teacher.objects.all()`之后我们可以注意到,在控制台看到的或者通过Django-Debug-Toolbar输出的SQL是下面这样的: + +```SQL +SELECT `tb_teacher`.`no`, `tb_teacher`.`name`, `tb_teacher`.`detail`, `tb_teacher`.`photo`, `tb_teacher`.`good_count`, `tb_teacher`.`bad_count`, `tb_teacher`.`sno` FROM `tb_teacher`; args=() +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` = 101; args=(101,) +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` = 101; args=(101,) +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` = 101; args=(101,) +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` = 101; args=(101,) +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,) +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()`方法来加载关联对象。 + +在导出老师Excel报表的视图函数中,我们可以按照下面的方式优化代码。 + +```Python +queryset = Teacher.objects.all().select_related('subject') +``` + +事实上,用ECharts生成前端报表的视图函数中,查询老师好评和差评数据的操作也能够优化,因为在这个例子中,我们只需要获取老师的姓名、好评数和差评数这三项数据,但是在默认的情况生成的SQL会查询老师表的所有字段。可以用`QuerySet`的`only()`方法来指定需要查询的属性,也可以用`QuerySet`的`defer()`方法来指定暂时不需要查询的属性,这样生成的SQL会通过投影操作来指定需要查询的列,从而改善查询性能,代码如下所示: + +```Python +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`中的元素是字典对象,每个字典中有三组键值对,分别是代表学科编号的`subject`、代表好评数的`good`和代表差评数的`bad`。如果想要获得学科的名称而不是编号,可以按照如下所示的方式调整代码: + +```Python +queryset = Teacher.objects.values('subject__name').annotate( + good=Avg('good_count'), bad=Avg('bad_count')) +``` + +可见,Django的ORM框架允许我们用面向对象的方式完成关系数据库中的分组和聚合查询。 \ No newline at end of file diff --git "a/Day41-55/47.\344\270\255\351\227\264\344\273\266\347\232\204\345\272\224\347\224\250.md" "b/Day41-55/47.\344\270\255\351\227\264\344\273\266\347\232\204\345\272\224\347\224\250.md" index 837bd169c..1f4c320a3 100644 --- "a/Day41-55/47.\344\270\255\351\227\264\344\273\266\347\232\204\345\272\224\347\224\250.md" +++ "b/Day41-55/47.\344\270\255\351\227\264\344\273\266\347\232\204\345\272\224\347\224\250.md" @@ -101,7 +101,7 @@ from django.shortcuts import redirect # 需要登录才能访问的资源路径 LOGIN_REQUIRED_URLS = { - '/praise/', '/criticize/', '/pdf/', '/excel/', + '/praise/', '/criticize/', '/excel/', '/teachers_data/', } @@ -143,4 +143,8 @@ MIDDLEWARE = [ 注意上面这个中间件列表中元素的顺序,当收到来自用户的请求时,中间件按照从上到下的顺序依次执行,这行完这些中间件以后,请求才会最终到达视图函数。当然,在这个过程中,用户的请求可以被拦截,就像上面我们自定义的中间件那样,如果用户在没有登录的情况下访问了受保护的资源,中间件会将请求直接重定向到登录页,后面的中间件和视图函数将不再执行。在响应用户请求的过程中,上面的中间件会按照从下到上的顺序依次执行,这样的话我们还可以对响应做进一步的处理。 -中间件执行的顺序是非常重要的,对于有依赖关系的中间件必须保证被依赖的中间件要置于依赖它的中间件的前面,就好比我们刚才自定义的中间件要放到`SessionMiddleware`的后面,因为我们要依赖这个中间件为请求绑定的`session`对象才能判定用户是否登录。 \ No newline at end of file +中间件执行的顺序是非常重要的,对于有依赖关系的中间件必须保证被依赖的中间件要置于依赖它的中间件的前面,就好比我们刚才自定义的中间件要放到`SessionMiddleware`的后面,因为我们要依赖这个中间件为请求绑定的`session`对象才能判定用户是否登录。 + +### 小结 + +至此,除了对用户投票数量加以限制的功能外,这个投票应用就算基本完成了,整个项目的完整代码请参考,其中用户注册时使用的手机验证码功能请大家使用自己注册的短信平台替代它。 \ No newline at end of file diff --git a/Day41-55/res/echarts_bar_graph.png b/Day41-55/res/echarts_bar_graph.png new file mode 100644 index 0000000000000000000000000000000000000000..a77571f7ad57622bf7da12465a630ed5bd2fa57b GIT binary patch literal 53301 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。之前每年都会试着为这个公益组织做一些自己能做的事情,这次当然也不能例外。 +2. Django部分(第41天到第55天)更新到第47天,最新上线的部分包括报表、日志、ORM查询优化以及中间件相关的内容,并将投票应用的完成代码同步到github。 +