赞
踩
highchart(Highcharts):国外的,不过也很好用。现在也出了中文文档
echarts(ECharts):国内的,也很不错,百度开发的。我们用echarts完成接下来的演示。
我们在此之前已经完成了较多工作,详情关注博主的Django专栏。我们接下来的工作也是在原来的页面的基础上进行的。
如上图所示,我们已经完成了管理员账户、部门管理、用户管理、靓号管理、任务管理、订单管理的界面,我们直接基于这几个界面完成接下来的数据统计工作。
先从简单的图表入手,我们计划完成柱状图、折现图、饼图的绘制。
先浅浅展示下结果
我们在完成简单的几种图之前,首先应该在原有的系统中设计新的界面用于数据统计。
这部分的思路还是传统的Django设计流程:首先修改模板html(我的是叫 layout.html
在其中添加一个能到达数据统计界面的按钮),然后在Django的urls.py
文件中添加新的路径(Django会通过这个路径管理网址以及每个页面对应的后端函数),接下来完成views.py
中对应的函数(函数有返回值,这里的返回值就是html文件),根据上一步的返回值完成对应的html文件(前端设计)。
修改模板html( layout.html
),修改后我们的界面顶部导航栏多了一个数据统计链接,点击后可以访问数据统计页面(<li><a href="/chart/list">数据统计</a></li>
)。
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Olsen</title> <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1-dist/css/bootstrap.min.css' %}"> <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1-dist/css/bootstrap-datetimepicker.min.css' %}"> <style> .navbar{ border-radius: 0; } </style> </head> <body> <nav class="navbar navbar-default"> <!-- <div class="container-fluid">--> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Olsen用户管理系统</a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li><a href="/admin/list">管理员账户</a></li> <li><a href="/depart/list">部门管理</a></li> <li><a href="/user/list">用户管理</a></li> <li><a href="/num/list">靓号管理</a></li> <li><a href="/task/list">任务管理</a></li> <li><a href="/order/list">订单管理</a></li> <li><a href="/chart/list">数据统计</a></li> </ul> <ul class="nav navbar-nav navbar-right"> <!-- <li><a href="#">登录</a></li>--> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ request.session.info.username }} <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">个人资料</a></li> <li><a href="#">我的信息</a></li> <li role="separator" class="divider"></li> <li><a href="/logout">注销</a></li> </ul> </li> </ul> </div> </div> </nav> <div> {% block content %} {% endblock %} </div> <script src="{% static 'js/jquery.js' %}"></script> <script src="{% static 'plugins/bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script> {% block js %} {% endblock %} </body> </html>
添加路径(urls.py
)。可以看到我们已经完成了很多的工作,只需要在路径列表中再加一条path('chart/list', chart.chart_list)
from django.urls import path from application01.views import depart, num, user, admin, account, task, order, chart urlpatterns = [ # path('admin/', admin.site.urls), path('depart/list', depart.depart_list), path('depart/add', depart.depart_add), path('depart/del', depart.depart_del), path('depart/<int:nid>/edit', depart.depart_edit), path('user/list', user.user_list), path('user/add', user.user_add), path('user/madd', user.user_madd), path('user/<int:nid>/edit', user.user_edit), path('user/<int:nid>/del', user.user_del), path('num/list', num.num_list), path('num/add', num.num_add), path('num/a', num.num_a), path('num/<int:nid>/edit', num.num_edit), path('num/<int:nid>/del', num.num_del), path('admin/list', admin.admin_list), path('admin/add', admin.admin_add), path('admin/<int:nid>/edit', admin.admin_edit), path('admin/<int:nid>/del', admin.admin_del), path('admin/<int:nid>/reset', admin.admin_reset), path('login', account.login), path('logout', account.logout), path('image/code', account.image_code), path('task/list', task.task_list), path('task/add', task.task_add), path('order/list', order.order_list), path('order/add', order.order_add), path('order/delete', order.order_delete), path('order/detail', order.order_detail), path('order/edit/', order.order_edit), path('chart/list', chart.chart_list) ]
完成views.py
中函数。因为界面比较多,我把原来的views.py拆成好几个文件,分别对应几个数据表,相关目录如下:
我们这里只是规划一个界面,先不整那些花里胡哨的东西,简简单单返回一个页面就好了。
# -*- coding:utf-8 -*-
from django.shortcuts import render
def chart_list(request):
return render(request, 'chart_list.html')
前端设计。继承在第一步写好的模板,再加上一点bootstrap官网里的模板代码。
{% extends 'layout.html' %} {% block content %} <div class="container"> <div class="panel panel-default"> <div class="panel-heading">折线图</div> <div class="panel-body"> ————————————--------- </div> </div> <div class="row"> <div class="col-sm-8"> <div class="panel panel-default"> <div class="panel-heading">柱状图</div> <div class="panel-body"> 1 1 11 <br> 1 1 11 <br> 1 1111 <br> 1111111<br> </div> </div> </div> <div class="col-sm-4"> <div class="panel panel-default"> <div class="panel-heading">饼图</div> <div class="panel-body"> O </div> </div> </div> </div> </div> {% endblock %}
最后,我们完成了页面的规划,最顶上方折线图,饼图和柱状图在下面共用一行。
注意,首先你必须要下载Echarts的js文件(Echarts),然后在echart官网中直接挑一款比较喜欢的图自己修改下配置即可。
我们意在统计不同部门的员工的平均年龄和部门员工数量。
{% extends 'layout.html' %} {% load static %} {% block content %} <div class="container"> <div class="panel panel-default"> <div class="panel-heading">折线图</div> <div class="panel-body"> <div id="l2" style="width: 100%;height:400px;"></div> </div> </div> <div class="row"> <div class="col-sm-7"> <div class="panel panel-default"> <div class="panel-heading">柱状图</div> <div class="panel-body"> <div id="m2" style="width: 100%;height:400px;"></div> </div> </div> </div> <div class="col-sm-5"> <div class="panel panel-default"> <div class="panel-heading">饼图</div> <div class="panel-body"> <div id="p1" style="width: 100%;height:400px;"></div> </div> </div> </div> </div> </div> {% endblock %} {% block js %} <script src="{% static 'js/echarts.js' %}"></script> <script type="text/javascript"> $(function () { initBar(); }) function initBar() { var myChart = echarts.init(document.getElementById('m2')); option_bar = { title: { text: '员工员工基本信息概览', textAlign: 'Auto', left: 'center', }, legend: { data:[], bottom: 0, }, tooltip: {}, xAxis: [{ type: 'category', data: [], }], yAxis: [ { type: 'value', name:'平均年龄', }, { type: 'value', name:'人数', } ], series: [ { data: [], type: 'bar' } ] } $.ajax({ url: "/chart/bar", type: "get", dataType: "JSON", success: function (res_bar) { if(res_bar.status){ option_bar.legend.data = res_bar.data.legend; option_bar.series = res_bar.data.series_list; option_bar.xAxis[0].data = res_bar.data.xAxis; myChart.setOption(option_bar); } } }) }; </script> {% endblock %}
后端数据处理代码如下,这边采取pandas完成输出的统计。
def chart_bar(request): row_obj = pd.DataFrame(models.User.objects.all().values("age", "Department__title")) data = row_obj.groupby("Department__title")['age'].describe() legend = ['平均年龄', '部门人数'] series_list = [ { 'name': '平均年龄', 'type': 'bar', 'data': data['mean'].tolist(), }, { 'name': '部门人数', 'type': 'bar', 'yAxisIndex': 1, 'data': data['count'].tolist(), }, ] xAxis = data.index.tolist() result = { "status": True, "data": { "legend": legend, "xAxis": xAxis, "series_list": series_list, } } return JsonResponse(result)
效果如下
利用饼图展示订单状态。
部分html代码如下,为模板语言中js部分的代码
{% block js %} <script src="{% static 'js/echarts.js' %}"></script> <script type="text/javascript"> $(function () { initPie(); }) function initPie() { var myChart = echarts.init(document.getElementById('p1')); option = { tooltip: { trigger: 'item' }, title: { text: '订单支付状态', textAlign: 'Auto', left: 'center', }, legend: { top: '90%', left: 'center' }, series: [ { name: 'Access From', type: 'pie', radius: ['40%', '70%'], avoidLabelOverlap: false, itemStyle: { borderRadius: 10, borderColor: '#fff', borderWidth: 2 }, label: { show: false, position: 'center' }, emphasis: { label: { show: true, fontSize: '40', fontWeight: 'bold' } }, labelLine: { show: false }, data: [ // { value: 1048, name: 'Search Engine' }, ] } ] }; $.ajax({ url: "/chart/pie", type: "get", dataType: "JSON", success: function (res) { if(res.status){ option.series[0].data = res.data.series_list; myChart.setOption(option); } } }) }; </script> {% endblock %}
数据处理用比较简单的ORM语言完成。
def chart_pie(request):
choice = dict(models.Order.status_choices)
series_list = models.Order.objects.values('status').annotate(count=Count('status'))
series_list = [{'name': choice[i["status"]], 'value':i['count']} for i in series_list]
result = {
"status": True,
"data": {
"series_list": series_list,
}
}
return JsonResponse(result)
展示下结果
折线图展示的是不同尾号的手机号码在不同VIP等级下的平均价格。
部分html代码如下,为模板语言中js部分的代码
{% block js %} <script src="{% static 'js/echarts.js' %}"></script> <script type="text/javascript"> $(function () { initLine(); }) function initLine() { var myChart = echarts.init(document.getElementById('l2')); option_line = { title: { text: '号码价格信息概览', textAlign: 'Auto', left: 'center', }, tooltip: { trigger: 'axis' }, legend: { data: [], orient: 'vertical', x:'right', //可设定图例在左、右、居中 y:'center', //可设定图例在上、下、居中 padding:[0,20,0,0], // data: ['Email', 'Union Ads', 'Video Ads', 'Direct', 'Search Engine'] }, grid: { top: '10%', left: '3%', right: '10%', bottom: '1%', containLabel: true }, toolbox: { feature: { saveAsImage: {} } }, xAxis: [{ type: 'category', boundaryGap: false, // data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }], yAxis: { type: 'value' }, series: [ ] }; $.ajax({ url: "/chart/line", type: "get", dataType: "JSON", success: function (res_line) { if(res_line.status){ option_line.legend.data = res_line.data.legend; option_line.series = res_line.data.series_list; option_line.xAxis[0].data = res_line.data.xAxis; console.log(res_line); myChart.setOption(option_line); } } }) }; </script> {% endblock %}
特意统计了个比较复杂的东西,还是用ORM语言完成。
def chart_line(request):
series_list = [models.YourNum.objects.filter(mobile__endswith=i) for i in range(10)]
series_list = [end_num.values('level').annotate(avg=Avg('price')).order_by("level") for end_num in series_list]
series_list = [{'name': "尾号"+str(index), 'type': 'line', 'data': [level_sorted['avg'] for level_sorted in end_with]} for index, end_with in enumerate(series_list)]
result = {
"status": True,
"data": {
"xAxis": [str(i+1)+"级" for i in range(5)],
"legend": [i['name'] for i in series_list],
"series_list": series_list,
}
}
# print(result)
return JsonResponse(result)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。