所有演示均基于Django2.0

阅读此篇文章你可以:

  • 了解Django中aggregate和annotate函数的使用方法
  • 获取一个Django+Echarts绘制柱状图的完整示例

需求说明

一张会议记录表,里边有一个字段存放会议举行的地点,例如北京、上海、洛阳等等,需要取举行会议最多的前20个地点绘制成柱状图展示,项目为前后端分离的架构

需求分析

看了需求主要有三个关键点:

1.前后端分离:前端只负责页面渲染,后端提供API负责数据输出

2.需要绘制成柱状图:绘制图表的第三方插件有很多,我们这里就选择百度开源的echarts,简单好用且功能强大

3.取举行会议最多的前20个地点:了解一点SQL知识的话就知道需要先要对地点字段进行group by,然后order by desc倒序,最后limit取前20

那么在Django中应该如何group by,并在group by之后order by排序,最后limit呢?这里我们介绍django的两个函数aggregateannotate

aggregate

aggregate聚合函数,用于对QuerySet整个对象结果的汇总,例如获取员工总数(COUNT),平均(AVG)年龄,最大(MAX)年龄,最小(MIN)年龄,销售总额(SUM)等,输出的结果是一个字典

我们有一个model如下:

class Employee(models.Model):
name = models.CharField(max_length=32, verbose_name='姓名')
age = models.IntegerField(verbose_name='年龄')
salary = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='薪资')

想要获取员工的工资总额,我们可以这样写

>>> from django.db.models import Sum

>>> Employee.objects.aggregate(Sum('salary'))
{'salary__sum': Decimal('5000.00')}

想要同时获取员工的平均年龄、最大年龄和最小年龄,我们可以这样写

>>> from django.db.models import Avg, Max, Min

>>> Employee.objects.aggregate(Avg('age'), Max('age'), Min('age'))
{'age__avg': 23.333333333333332, 'age__max': 30, 'age__min': 18}

annotate

annotate函数区别于aggregate函数的一个最重要的地方是annotate函数输出的结果是一个QuerySet对象,这个非常重要,aggregate函数最后输出的结果是个字典,也就不能再在字典的基础上进行QuerySet操作了,而annotate函数执行完成后输出QuerySet对象可以继续调用Django内置的filter、order_by等函数来完成更加复杂的查询计算操作

用到annotate函数的逻辑往往比较复杂,Django非常人性化的提供了query方法,方便查看annotate生成的SQL语句帮助我们确定执行过程

以上边的实际需求为例,model如下:

class EventInfo(models.Model):
event_location = models.CharField(max_length=30) class Meta:
db_table = "app_event_info"

我们需要先对地点event_location进行group by:

>>> _t = EventInfo.objects.values_list('event_location').annotate(Count('id'))

# values_list可以获取evnet_location的元组列表。
# values_list方法加个参数flat=True可以获取event_location的值列表。

group by之后我们就需要order by排序了,如果我们不知道order by的字段,我们可以通过query先查看group by生成的SQL语句

>>> print(_t.query)
SELECT "app_event_info"."event_location", COUNT("app_event_info"."id") AS "id__count" FROM "app_event_info" GROUP BY "app_event_info"."event_location"

这个时候可以看到实际上输出的结果有一个叫id__count的字段表示地点的总数,那么我们就可以接着对地点总数进行排序了,因为是要倒叙,需要在字段名id__count前边加上-号来表示倒序

>>> _x = _t.order_by('-id__count')
>>>
>>> print(_x.query)
SELECT "app_event_info"."event_location", COUNT("app_event_info"."id") AS "id__count" FROM "app_event_info" GROUP BY "app_event_info"."event_location" ORDER BY "id__count" DESC

最后limit取前二十,Django中limit可以直接通过QuerySet结果后加python的数组切片语法来实现,就像[0:20](其中0可以省略)相当于limit 20一样,[10:20]意思为取第10到第20条数据

>>> _y = _x[:20]
>>>
>>> print(_y.query)
SELECT "app_event_info"."event_location", COUNT("app_event_info"."id") AS "id__count" FROM "app_event_info" GROUP BY "app_event_info"."event_location" ORDER BY "id__count" DESC LIMIT 20

上边的每一步我们都通过query打印了SQL,确定是我们想要的结果了。需求分析清楚,所有的关键点我们也都知道怎么处理了,那么接下来实现就水到渠成了。

实现代码

URL如下:

from django.urls import path
from django.views.generic.base import TemplateView from .views import echarts_data
urlpatterns = [
path('echarts/', TemplateView.as_view(template_name='echarts.html'), name='echarts-url'), path('api/echarts/', echarts_data, name='api-echarts')
]

因为是前后端分离的,所以我这里用了两个urlechartsapi/echarts

echarts为前台访问地址,对应下边的html代码,通过ajax方式调用后端接口,所以这里直接用了TemplateView,不需要再写额外的view代码

api/echarts为后端API的地址,对应下边的view代码,为前台提供数据接口

前端HTML:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ops-coffee</title>
<!-- 引入 echarts.js -->
<script src="/static/js/jquery.min.js"></script>
<script src="/static/js/echarts/echarts.common.min.js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main')); $.ajax({
type: "get",
url: "/api/echarts",
dataType: "json",
success: function (data) { // 指定图表的配置项和数据
var option = {
title: {
left: 'center',
text: 'ops-coffee 运维咖啡吧'
},
tooltip: {},
xAxis: {
data: data.key
},
yAxis: {},
series: [{
name: '数量',
type: 'bar',
data: data.value
}]
}; // 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
},
error: function () {
alert('Error: ajax 请求出错!')
}
});
</script>
</body>
</html>

实例比较简单,抄的echarts官方示例,这里会看到echarts渲染图形实际上只需要X轴和Y轴两个数据变量,且都为list列表类型

后端VIEW:

文章未完,全部内容请关注公众号【运维咖啡吧】或个人网站https://ops-coffee.cn查看,运维咖啡吧专注于原创精品内容分享,感谢您的支持

Django+Echarts画图实例的更多相关文章

  1. echarts画图时tooltip.formatter参数params不会更新(转载)

    echarts画图时tooltip.formatter参数params不会更新 解决方案: setOption时默认是合并, 如果要全部重新加载 要写成 setOption({},true),这样就可 ...

  2. vue父组件异步传递prop到子组件echarts画图问题踩坑总结

    效果图: 大致思路:考虑到5张图都是折线图,所以准备用一个子组件承接echarts画图,然后父组件通过prop传递不同数据来展示不同的图 踩坑问题: 1.引入line子组件,画了5个元素,但是只显示一 ...

  3. matplotlib画图实例:pyplot、pylab模块及作图參数

    http://blog.csdn.net/pipisorry/article/details/40005163 Matplotlib.pyplot画图实例 {使用pyplot模块} matplotli ...

  4. Django 过滤器 实例

    实例1 safe让Html标签以及一些特殊符号(如<)生效,下面以例子说明: # value = '<b>CPT</b>' # 那么输出的时候,CPT就是加粗的,如果不加 ...

  5. 实战Django:官方实例Part6

    我们终于迎来了官方实例的最后一个Part.在这一节中,舍得要向大家介绍Django的静态文件管理. 现在,我们要往这个投票应用里面添加一个CSS样式表和一张图片. 一个完整的网页文件,除了html文档 ...

  6. 实战Django:官方实例Part5

    俗话说,人非圣贤,孰能无过.在堆代码的过程中,即便是老攻城狮,也会写下一些错误的内容.俗话又说,过而能改,善莫大焉.要改,首先要知道哪里存在错误,这便是我们要对投票应用进行测试的原因.   21.撰写 ...

  7. ECharts 使用实例

    HTML与JavaScript代码: <%@ page language="java" contentType="text/html; charset=UTF-8& ...

  8. django+echarts

    思路: 统一返回数据类型为json,然后前端发起Ajax请求后台数据接口 views.py def count_blog(request): # 下面等价于:select distinct auth, ...

  9. Baidu - Echarts 地图实例测试,并绘制平滑圆弧路径

    百度Echarts实例地址: http://echarts.baidu.com/examples.html 同事想做一个地图,地图上的几个点通过动态的线连接起来.但是在实例里没找到类似的. 然后仔细分 ...

随机推荐

  1. Establish a website in 5 minutes

    $sudo apt-get update                                    //update   $sudo apt-get install tasksel     ...

  2. java基础-day19

    第08天 异常 今日内容介绍 u  异常体系&异常处理 u  Throwable常用方法&自定义异常 u  递归 第1章   异常产生&异常处理 1.1      异常概述 什 ...

  3. JVM虚拟机-类加载器子系统

    转自博客:http://www.cnblogs.com/muffe/p/3541189.html   还有一些自己补充的知识点 一.类加载器基本概念 顾名思义,类加载器(class loader)用来 ...

  4. scikit-FEM-例2-用Morley元在方形区域上解板弯曲问题

    """ Author: kinnala Solve the Kirchhoff plate bending problem in a unit square with c ...

  5. 5.Django高级

    管理静态文件 项目中的CSS.图片.js都是静态文件 配置静态文件 在settings 文件中定义静态内容 STATIC_URL = '/static/' STATICFILES_DIRS = [ o ...

  6. PHP内存溢出Allowed memory size of 解决办法

    PHP内存溢出Allowed memory size of 解决办法 博客分类: php   ============================Allowed memory size of  x ...

  7. WinDbg探究CLR底层(1) - 应用程序域

    一.什么是应用程序域 操作系统由于其稳定性与可靠性的要求,都会使用隔离层,来确保运行在某个隔离层内的代码不会对其他隔扇层的代码产生影响.如Windows通过进程来实现这种隔离机制,所能的可执行代码.数 ...

  8. WPF 分享一种背景动画效果

    今天看微软的一个Samples,发现一个蛮好玩的背景样式,如下图所示: 风格比较卡哇伊. <Window x:Class="WPFSamplesTest.MainWindow" ...

  9. AngularJs从数据库获取数据并显示

    哈哈,昨天下午和今天早上,花上一些时间,学习AngularJs,仅是粗略预览一下.很好,非常好. 由于手上有开发ASP.NET MVC环境,就在这测试下,去数据库获取数据并显示数据. 数据库表创建,添 ...

  10. Shell命令之文本操作

    前言 在Linux中,文本处理操作是最常见的,应用非常广泛,如果能熟练掌握,可以大大提高开发效率. awk/sed/grep是文本操作领域的“三剑客”,学会了这3个命令就可以应对绝大多数文本处理场景. ...