从零开始的Django框架入门到实战教程(内含实战实例) - 11 利用echart和Ajax请求完成数据可视化(学习笔记)

11 篇文章 47 订阅


  Django是目前比较火爆的框架,之前有在知乎刷到,很多毕业生进入大厂实习后因为不会git和Django框架3天就被踢掉了,因为他们很难把自己的工作融入到整个组的工作中。因此,我尝试自学Django并整理出如下笔记。
  主要内容包括echart插件最基本的使用(套模板),Ajax传输请求和数据,ORM和pandas数据统计与分析。
  作为一个管理系统,数据统计功能是必不可少的,系统中数据庞杂,若无一个较好的可视化界面,个人认为这个管理系统还存在很大的提升空间。
  数据可视化离不开图表,方便起见,我将使用插件完成简单的图标制作。介绍两个比较大的图表插件:

  • highchart(Highcharts):国外的,不过也很好用。现在也出了中文文档

  • echarts(ECharts):国内的,也很不错,百度开发的。我们用echarts完成接下来的演示。

0. 既有工作

  我们在此之前已经完成了较多工作,详情关注博主的Django专栏。我们接下来的工作也是在原来的页面的基础上进行的。
在这里插入图片描述

  如上图所示,我们已经完成了管理员账户、部门管理、用户管理、靓号管理、任务管理、订单管理的界面,我们直接基于这几个界面完成接下来的数据统计工作。

  先从简单的图表入手,我们计划完成柱状图、折现图、饼图的绘制。

1. 结果展示

  先浅浅展示下结果
在这里插入图片描述

2. 页面设计

  我们在完成简单的几种图之前,首先应该在原有的系统中设计新的界面用于数据统计。

  这部分的思路还是传统的Django设计流程:首先修改模板html(我的是叫 layout.html 在其中添加一个能到达数据统计界面的按钮),然后在Django的urls.py文件中添加新的路径(Django会通过这个路径管理网址以及每个页面对应的后端函数),接下来完成views.py中对应的函数(函数有返回值,这里的返回值就是html文件),根据上一步的返回值完成对应的html文件(前端设计)。

  修改模板htmllayout.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 %}

  最后,我们完成了页面的规划,最顶上方折线图,饼图和柱状图在下面共用一行。

在这里插入图片描述

3. 柱状图

  注意,首先你必须要下载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)

  效果如下

在这里插入图片描述

4. 饼图

  利用饼图展示订单状态。

在这里插入图片描述

  部分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)

5. 折线图

  展示下结果
在这里插入图片描述

  折线图展示的是不同尾号的手机号码在不同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)
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
1.项目代码功能经验证ok,确保稳定可靠运行。欢迎下载使用!在使用过程中,如有问题或建议,请及时私信沟通。 2.主要针对各个计算机相关专业,包括计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师或企业员工使用。 3.项目具有丰富的拓展空间,不仅可作为入门进阶,也可直接作为毕设、课程设计、大作业、初期项目立项演示等用途。 4.当然也鼓励大家基于此进行二次开发。 5.期待你能在项目中找到乐趣和灵感,也欢迎你的分享和反馈! 【资源说明】 基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip 基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip 基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip 基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip 基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip 基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip 基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip 基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip 基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip 基于Django框架的PM2.5空气质量数据可视化及分析系统python源码+数据库(毕业设计).zip

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铖铖的花嫁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值