文档章节

Django+Echarts画图实例

运维咖啡吧
 运维咖啡吧
发布于 2018/11/26 07:47
字数 1637
阅读 1323
收藏 8

所有演示均基于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:

from django.http import JsonResponse
from django.db.models import Count

from .models import EventInfo

def echarts_data(request):
    _x = EventInfo.objects.values_list('event_location').annotate(Count('id')).order_by('-id__count')[:20]

    jsondata = {
        "key": [i[0] for i in _x],
        "value": [i[1] for i in _x]
    }

    return JsonResponse(jsondata)

最核心的那行group by + order by + limit的ORM拼接,我们上边已经详细的介绍过了,那么这里只需要在输出的结果中单独的把城市跟数量转成两个列表对应echarts里边需要的X轴Y轴数据就可以了

最后访问url:https://ops-coffee.cn/echarts 可以看到我们想要的结果

整个Demo示例介绍完成。


长按关注公众号查看更多原创文章

如果你觉得文章对你有帮助,请转发分享给更多的人。如果你觉得读的不尽兴,推荐阅读以下文章:

© 著作权归作者所有

运维咖啡吧
粉丝 36
博文 43
码字总数 76876
作品 1
浦东
架构师
私信 提问
加载中

评论(2)

a
afrunk-7

引用来自“afrunk-7”的评论

博主你好,我在后端传过来的json数据连接下可以看到具体的数据,为什么在前端可视化的渲染页面看不到任何东西呢?我检查之后发现HTML是传过来了,但是没有可视化的效果,你觉得会有哪些原因导致这样的情况?
已解决:原因是js文件没有导入导致404,是django的问题,在设置中配置即可!
a
afrunk-7
博主你好,我在后端传过来的json数据连接下可以看到具体的数据,为什么在前端可视化的渲染页面看不到任何东西呢?我检查之后发现HTML是传过来了,但是没有可视化的效果,你觉得会有哪些原因导致这样的情况?
Django集成Markdown编辑器【附源码】

专注内容写作的你一定不要错过markdown 简单介绍 markdown是一种标记语言,通过简单的标记语法可以使普通的文本内容具有一定的格式,使用非常简单,学习成本极低 目前各大Blog平台都已支持m...

运维咖啡吧
01/24
47
0
Django开发密码管理表实例【附源码】

  文章及代码比较基础,适合初、中级人员,高手略过      阅读此篇文章你可以:      获取一个Django实现增删改查的案例源码      了解数据加密的使用场景和方法以及如何在Pyt...

SEOwhywhy
2018/12/06
19
0
Unity的动画图和人形动画初探

版权声明:本文所有文章均为原创,原文链接:blog.uwa4d.com,如需转载请联系support@uwa4d.com https://blog.csdn.net/UWA4D/article/details/87172998 这是侑虎科技第504篇文章,感谢作者加...

UWA
02/20
0
0
matlab导入txt数据画图

因为最近需要观察txt保存的一堆数据,则需要使用这些数据画图。 强大的matlab分分钟解决了。 实例 数据:data.txt 步骤: ①打开matlab -> HOME(主页) -> Import Data(导入数据) ②选择data....

Devil-wei
02/16
0
0
Gnuplot:双折线图、双柱状图模板

一、下载下载地址:https://sourceforge.net/projects/gnuplot/files/gnuplot/ 我下载的版本:gp504-win64-mingw.exe 直接安装即可,没什么需要注意的。 二、画图说明在画图时,需要一个数据...

quiet_girl
2017/08/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

centos7 安装 mysql5.7 版本(全)

centos 安装 版本说明 :centos7,mysql5.7 ,不是 centos7 可能有些命令不兼容 安装 mysql-server # 下载并安装 mysql yum wget -i -c http://dev.mysql.com/get/mysql57-community-relea......

sanri1993
27分钟前
4
0
Spring3.x升级到Spring4.x-5.x时关于MappingJacksonHttpMessageConverter的报错问题

在Spring4.x或者以上的版本强使用(不然会报错): org.springframework.http.converter.json.MappingJackson2HttpMessageConverter 如果是Spring4.0获者以下的版本可以使用MappingJacksonH...

code-ortaerc
30分钟前
3
0
OSG 渲染状态污染到其它节点怎么解决?

在根节点补上初始状态

洛克人杰洛
32分钟前
3
0
grid 布局 设置行列间距

本文转载于:专业的前端网站➪grid 布局 设置行列间距 <!DOCTYPE html><html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="widt......

前端老手
44分钟前
3
0
spring-data-elasticsearch 和 Jackson 配合使用的bug

下面先简单描述项目。 项目依赖: dependencies { implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-elasticsearch', version: '2.1.0.RELEASE'......

Landas
45分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部