Django学习记录08——图表及文件上传案例

1.图表Echarts的应用

Apache ECharts

1.1 使用方法

引用echarts.js即可到官方文档中查询使用

1.2 常用图标的使用

图表展示页面的部署(主要展示折线图、柱状图、饼图)

html 复制代码
{% block content %}
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">折线图</h3>
            </div>
            <div class="panel-body">
                <div id="m1" style="width: 100%;height:500px;"></div>
            </div>
        </div>
        <div class="row">
            <div class="col-sm-8">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title">柱状图</h3>
                    </div>
                    <div class="panel-body">
                        <div id="m2" style="width: 100%;height:400px;"></div>
                    </div>
                </div>
            </div>
            <div class="col-sm-4">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title">饼图</h3>
                    </div>
                    <div class="panel-body">
                        <div id="m3" style="width: 100%;height:400px;"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
{% endblock %}

使用方法

var myChart = echarts.init(document.getElementById('m1')); 基于准备好的dom,初始化echarts实例 根据id获取展示的位置

option = {官方文档获取 }; 指定图表的配置项和数据

myChart.setOption(option); 使用刚指定的配置项和数据显示图表。

1.2.1 折线图

  • 官方文档代码
option = {
  title: {
    text: 'Stacked Line'
  },
  tooltip: {
    trigger: 'axis'
  },
  legend: {
    data: ['Email', 'Union Ads', 'Video Ads', 'Direct', 'Search Engine']
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '3%',
    containLabel: true
  },
  toolbox: {
    feature: {
      saveAsImage: {}
    }
  },
  xAxis: {
    type: 'category',
    boundaryGap: false,
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      name: 'Email',
      type: 'line',
      stack: 'Total',
      data: [120, 132, 101, 134, 90, 230, 210]
    },
    {
      name: 'Union Ads',
      type: 'line',
      stack: 'Total',
      data: [220, 182, 191, 234, 290, 330, 310]
    },
    {
      name: 'Video Ads',
      type: 'line',
      stack: 'Total',
      data: [150, 232, 201, 154, 190, 330, 410]
    },
    {
      name: 'Direct',
      type: 'line',
      stack: 'Total',
      data: [320, 332, 301, 334, 390, 330, 320]
    },
    {
      name: 'Search Engine',
      type: 'line',
      stack: 'Total',
      data: [820, 932, 901, 934, 1290, 1330, 1320]
    }
  ]
};
  • 使用

在html中id为m1的标签,展示折线图

html 复制代码
    <script type="text/javascript">
        $(function () {
            initLine();
        })

        //初始化折线图
        function initLine() {
            // 基于准备好的dom,初始化echarts实例
            var myChart = echarts.init(document.getElementById('m1'));
            // 指定图表的配置项和数据
            var option = {
                title: {
                    text: '分公司上半年业绩'
                },
                tooltip: {
                    trigger: 'axis'
                },
                legend: {
                    data: [数据]
                },
                grid: {
                    left: '3%',
                    right: '4%',
                    bottom: '3%',
                    containLabel: true
                },
                toolbox: {
                    feature: {
                        saveAsImage: {}
                    }
                },
                xAxis: {
                    type: 'category',
                    boundaryGap: false,
                    data: [数据]//待后端传来的数据
                },
                yAxis: {
                    type: 'value'
                },
                series: [数据]//待后端传来的数据
            };
            //使用ajax请求从后台获取数据
            $.ajax({
                url: '/chart/line',
                type: 'get',
                dataType: 'json',
                success: function (res) {
                    //在此对图标的x轴,y轴,图例等进行赋值
                    if (res.status) {
                        //重新赋值
                        option.legend.data = res.data.legend_data;
                        option.xAxis.data = res.data.x_data;
                        option.series = res.data.series;

                        // 使用刚指定的配置项和数据显示图表。
                        myChart.setOption(option);
                    }

                }
            })

        }
    </script>
  • 基本属性

title 图表标题的相关属性

legend 图例的相关属性

xAxis x轴的相关属性

series y轴展示内容的属性

  • 数据的获取

对于option{}中各属性的数据内容可从后端的视图函数(视图函数从数据库)中获取\

使用Aajx请求获取后台数据,并传给option

chart.py视图函数

py 复制代码
def chart_line(request):
   """构造折线图"""
   # 模拟从数据库获取数据
   legend_data = ['公司1', '公司2', '公司3', '公司4', '公司5']
   x_data = ['1月份', '2月份', '3月份', '4月份', '5月份', '6月份']
   series = [
       {
           'name': '公司1',
           'type': 'line',
           'stack': 'Total',
           'data': [120, 1322, 1201, 134, 920, 2320, 210]
       },
       {
           'name': '公司2',
           'type': 'line',
           'stack': 'Total',
           'data': [220, 1832, 191, 2324, 290, 3230, 310]
       },
       {
           'name': '公司3',
           'type': 'line',
           'stack': 'Total',
           'data': [1510, 2232, 201, 1524, 190, 330, 410]
       },
       {
           'name': '公司4',
           'type': 'line',
           'stack': 'Total',
           'data': [3230, 332, 3021, 334, 3930, 330, 320]
       },
       {
           'name': '公司5',
           'type': 'line',
           'stack': 'Total',
           'data': [820, 932, 901, 934, 1290, 1330, 1320]
       }
   ]

   data_dict = {
       'status': True,
       'data': {
           'legend_data':legend_data,
           'x_data': x_data,
           'series': series,
       }
   }
   return JsonResponse(data_dict)

以上在视图函数中模拟数据库数据传到前端中

数据传输到前端后,Ajax请求对option的各个属性进行赋值

js 复制代码
option.legend.data = res.data.legend_data;
option.xAxis.data = res.data.x_data;
option.series = res.data.series;

1.2.2 柱状图

  • 官方文档代码
option = {
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [120, 200, 150, 80, 70, 110, 130],
      type: 'bar'
    }
  ]
};
  • 使用

在html中id为m2的标签,展示柱状图

html 复制代码
    <script type="text/javascript">
        $(function () {
            initBar();
        })

        //初始化柱状图
	function initBar() {
            // 基于准备好的dom,初始化echarts实例
            var myChart = echarts.init(document.getElementById('m2'));

            // 指定图表的配置项和数据
            var option = {
                title: {
                    text: '员工业绩',
                    left: 'center',
                },
                tooltip: {},
                //图例
                legend: {
                    data: [数据],//待后端传来的数据
                    bottom: 0,
                },
                //x轴
                xAxis: {
                    data: []  //待后端传来的数据
                },
                //y轴
                yAxis: {},
                series: []  //待后端传来的数据

            };
            //使用ajax请求从后台获取数据
            $.ajax({
                url: '/chart/bar',
                type: 'get',
                dataType: 'json',
                success: function (res) {
                    //在此对图标的x轴,y轴,图例等进行赋值
                    if (res.status) {
                        //重新赋值
                        option.legend.data = res.data.legend;
                        option.xAxis.data = res.data.x_data;
                        option.series = res.data.series;

                        // 使用刚指定的配置项和数据显示图表。
                        myChart.setOption(option);
                    }

                }
            })
        }
    </script>
  • 基本属性

title 图表标题的相关属性

legend 图例的相关属性

xAxis x轴的相关属性

series y轴展示内容的属性

  • 数据的获取

对于option{}中各属性的数据内容可从后端的视图函数(视图函数从数据库)中获取\

使用Aajx请求获取后台数据,并传给option

chart.py视图函数

py 复制代码
def chart_bar(request):
   # 模拟数据库获取图表数据   以下可使用数据库获取
   legend = ['YQY', 'WYT']
   x_data = ['1月', '2月', '3月', '4月', '5月', '6月']
   series = [
       {
           'name': 'YQY',
           'type': 'bar',
           'data': [5, 20, 36, 10, 10, 20],
       },
       {
           'name': 'WYT',
           'type': 'bar',
           'data': [15, 40, 86, 90, 22, 88]
       }
   ]

   data_dict = {
       'status': True,
       'data': {
           'legend': legend,
           'x_data': x_data,
           'series': series,
       }
   }
   return JsonResponse(data_dict)

以上在视图函数中模拟数据库数据传到前端中

数据传输到前端后,Ajax请求对option的各个属性进行赋值

js 复制代码
option.legend.data = res.data.legend;
option.xAxis.data = res.data.x_data;
option.series = res.data.series;

1.2.2 饼状图

  • 官方文档代码
js 复制代码
option = {
  title: {
    text: 'Referer of a Website',
    subtext: 'Fake Data',
    left: 'center'
  },
  tooltip: {
    trigger: 'item'
  },
  legend: {
    orient: 'vertical',
    left: 'left'
  },
  series: [
    {
      name: 'Access From',
      type: 'pie',
      radius: '50%',
      data: [
        { value: 1048, name: 'Search Engine' },
        { value: 735, name: 'Direct' },
        { value: 580, name: 'Email' },
        { value: 484, name: 'Union Ads' },
        { value: 300, name: 'Video Ads' }
      ],
      emphasis: {
        itemStyle: {
          shadowBlur: 10,
          shadowOffsetX: 0,
          shadowColor: 'rgba(0, 0, 0, 0.5)'
        }
      }
    }
  ]
};
  • 使用

在html中id为m3的标签,展示饼状图

html 复制代码
    <script type="text/javascript">
        $(function () {
            initPie();
        })

        //初始化饼状图
    function initPie() {
            // 基于准备好的dom,初始化echarts实例
            var myChart = echarts.init(document.getElementById('m3'));

            // 指定图表的配置项和数据
            var option = {
                title: {
                    text: '部门预算',
                    subtext: '副标题',
                    left: 'center'
                },
                tooltip: {
                    trigger: 'item'
                },
                legend: {
                    orient: 'vertical',
                    left: 'left',
                    bottom: 0,
                },
                series: [
                    {
                        name: '预算',
                        type: 'pie',
                        radius: '50%',
                        data: [], //待后端传来的数据
                        emphasis: {
                            itemStyle: {
                                shadowBlur: 10,
                                shadowOffsetX: 0,
                                shadowColor: 'rgba(0, 0, 0, 0.5)'
                            }
                        }
                    }
                ]
            };

            //使用ajax请求从后台获取数据
            $.ajax({
                url: '/chart/pie',
                type: 'get',
                dataType: 'json',
                success: function (res) {
                    //在此对图标的x轴,y轴,图例等进行赋值
                    if (res.status) {
                        //重新赋值
                        /*
                        series: [{name: '预算',type: 'pie',radius: '50%',data: [],}]
                        series 是一个仅有一个字典元素的列表,
                        series[0]取列表第一个元素,也就是这个字典
                        series 为仅含有一个字典元素的列表,series[0].data表示取出series列表的第一个字典元素的data键
                         */
                        option.series[0].data = res.data;

                        // 使用刚指定的配置项和数据显示图表。
                        myChart.setOption(option);
                    }

                }
            })
        }
    </script>
  • 基本属性

title 图表标题的相关属性

legend 图例的相关属性

xAxis x轴的相关属性

series y轴展示内容的属性

  • 数据的获取

对于option{}中各属性的数据内容可从后端的视图函数(视图函数从数据库)中获取\

使用Aajx请求获取后台数据,并传给option

chart.py视图函数

py 复制代码
def chart_pie(request):
   '''构造饼图数据'''
   # 模拟从数据库获取数据
   series_data = [
       {'value': 1048, 'name': 'IT部门'},
       {'value': 735, 'name': '销售部'},
       {'value': 580, 'name': '宣传部'},
   ]
   data_dict = {
       'status': True,
       'data': series_data,
   }
   return JsonResponse(data_dict)

以上在视图函数中模拟数据库数据传到前端中

数据传输到前端后,Ajax请求对option的各个属性进行赋值

js 复制代码
option.series[0].data = res.data;

2.文件的上传

2.1 基础操作

html上传页面

html 复制代码
<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="text" name="username">
    <input type="file" name="avatar">
    <input type="submit" value="提交">
</form>
py 复制代码
def upload_file(request):
    if request.method == 'GET':
        return render(request, 'upload_file.html')
    
    file_object = request.FILES['photo']  # 获取文件对象
    print(file_object.name)  # 获取文件名称

    # 生成文件名为file_object.name的文件
    f = open(file_object.name, mode='wb')
    # 由于文件在内存一块一块的存储,利用循环遍历每一块,写入f中
    for chunk in file_object.chunks():  # chunks()读取文件对象的内容
        f.write(chunk)
    f.close()
    return HttpResponse('上传成功')

request.POST 返回所有数据的组成的数据对象
request.FILES返回所有文件组成的数据对象

py 复制代码
enctype="multipart/form-data"   
form标签中若不加此字段,上传的文件以文件名的形式通过request.POST传过来:
<QueryDict: {'csrfmiddlewaretoken': ['6oGNXjBGaHzqFGywRFd7JQWXrY7fQwB6cEURubTTxemKDA789nRjb3Kv5MEgYnOE'], 'username': ['123'], 'photo': ['20220829_20471734.jpg']}>

form标签加上此字段,上传的文件以文件的形式通过request.FILES传过来
<MultiValueDict: {}>

file_object = request.FILES['photo'] 获取文件对象(input框中name为photo的输入数据)
file_object.name 获取文件名称

f = open(file_object.name, mode='wb') 生成文件名为file_object.name的文件

py 复制代码
# 由于文件在内存一块一块的存储,利用循环遍历每一块,写入f中
for chunk in file_object.chunks():  # chunks()读取文件对象的内容
	f.write(chunk)
f.close()

选择上传的图片后,点击提交按钮,图片会以post的方式传入视图函数,通过file_object = request.FILES['photo']获取文件对象,并且chunks()读取文件对象的内容,最终将图片下载到项目目录中

2.2通过文件批量上传数据

将excel中存在部门批量添加到部门列表中

部门页面增加批量上传按钮

html 复制代码
<form method="post" enctype="multipart/form-data" action="/depart/multi">
	{% csrf_token %}
	<div class="form-group">
		<input type="file" name="exc">
	</div>
	<input type="submit" value="上传" class="btn-primary btn-sm">
</form>
py 复制代码
def depart_multi(request):
    """批量添加excel文件内的数据"""
    # 1.获取上传的文件对象
    file_object = request.FILES.get("exc")
    print(file_object)
    # 2.对象传递给openpyxl,有openpyxl读取文件内容
    wb = load_workbook(file_object)
    sheet = wb.worksheets[0] # 获取表
    print(sheet) #<Worksheet "Sheet1">
    print(sheet.cell(2,1).value) #部门1

    # 3.循环获取每一个数据
    # 遍历sheet的每一行,从第二行开始
    for row in sheet.iter_rows(min_row=2):
        # 获取每行第一列的值
        title = row[0].value
        # 先判断部门是否存在
        flag = models.Department.objects.filter(title=title).exists()
        if not flag:
            models.Department.objects.create(title=title)
    return redirect('/depart/list')

file_object = request.FILES.get("exc") 获取上传的文件对象

wb = load_workbook(file_object)对象传递给openpyxl,有openpyxl读取文件内容

sheet = wb.worksheets[0] 获取表

sheet.iter_rows(min_row=2) 遍历sheet的每一行,从第二行开始

2.3 ModelForm实现文件上传

2.3.1 media的应用

  • static,存放静态文件的路径,包括:CSS、JS、项目图片。
  • media,用户在前端上传的数据的目录(文件均存在此文件的子文件中)。

media的启用

url.py中配置

py 复制代码
from django.urls import path, re_path
from django.views.static import serve
from django.conf import settings

urlpatterns = [
    
	re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
    
]

settings.py中配置

py 复制代码
import os

MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"

完成操作后,可以通过http://localhost:8000/media/xxx 来访问文件(xxx表示文件相对media的位置)

2.3.2 ModelForm实现city展示案例

models.py

py 复制代码
class City(models.Model):
    """城市"""
    name = models.CharField(max_length=32,verbose_name="名称")
    count = models.IntegerField(verbose_name="人口")
    # 虽是FileField,但是本质上还是charField
    img = models.FileField(verbose_name="Logo",max_length=128,upload_to="city/")

img = models.FileField(verbose_name="Logo",max_length=128,upload_to="city/")

**upload_to = xxx 上传到 media/xxx目录中(不写默认上传到media目录) **

此时上传的图片自动存储到media/city/1.png

ModelForm定义

py 复制代码
class UpMoldelForm(BootStrapModelForm):
    bootstrap_exclude_fields = ['img']

    class Meta:
        model = models.City
        fields = ['name', 'count', 'img']

bootstrap_exclude_fields = ['img'] img字段不使用BootStrapModelForm的输入框样式

city_add.html

html 复制代码
{% extends 'layout.html' %}

{% block content %}
    <div class="panel panel-default">
        <div class="panel-heading">{{ title }}</div>
        <div class="panel-body">
            <form class="form" method="post" enctype="multipart/form-data" novalidate>
                {% csrf_token %}
                {% for field in form %}
                    <div class="form-group">
                        <label>{{ field.label }}</label>
                        {{ field }}
                        <span style="color: red">{{ field.errors.0 }}</span>
                        {#                        field.errors.0显示第一条错误即可#}
                    </div>
                {% endfor %}
                <input type="submit" class="btn btn-success" value="提交">
            </form>
        </div>
    </div>
{% endblock %}

视图函数city_add()

py 复制代码
def upload_ModelForm(request):
    """ 上传文件和数据"""
    if request.method == 'GET':
        # 构造添加输入框
        form = UpMoldelForm()
        context = {
            'form': form,
            'title': 'ModelForm',
        }
        return render(request, 'upload_ModelForm.html', context)
    form = UpMoldelForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        # 对于文件来说,自动保存定义时的路径位置  默认在media下  (media/city)
        # 保存文件的路径和名称   img:city/blog.png
        form.save()
        return redirect("/upload/city_list")
    context = {
        'form': form,
        'title': 'ModelForm',
    }
    return render(request, 'upload_ModelForm.html', context)

form = UpMoldelForm(data=request.POST, files=request.FILES) 获取前端的数据及文件

form.save() 在ModelForm中直接使用此语句进行保存数据到数据库**(数据库文件字段保存文件的路径和名称 img:city/blog.png)**

对于文件来说,自动保存定义时的路径位置 默认在media下 (media/city)

city_list.html

html 复制代码
{% extends 'layout.html' %}

{% block content %}
    <div style="margin-bottom: 10px">
        <a type="button" class="btn btn-success" href="/upload/ModelForm"><span class="glyphicon glyphicon-plus-sign"
                                                                         aria-hidden="true"></span> 添加城市</a>

    </div>
    <div class="panel panel-default">
        <div class="panel-heading">城市列表</div>
        <div class="bs-example" data-example-id="hoverable-table">
            <table class="table table-hover">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>名称</th>
                    <th>人口</th>
                    <th>Logo</th>
                </tr>
                </thead>
                <tbody>
                {% for obj in queryset %}
                    <tr>
                        <td>{{ obj.id }}</td>
                        <td>{{ obj.name }}</td>
                        <td>{{ obj.count }}</td>
                        <td>
                            {# obj.img图片相对于media的路径 #}
                            <img src="/media/{{ obj.img }}" style="height: 40px">
                        </td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
{% endblock %}

city_list()的视图函数

py 复制代码
def city_list(request):
    queryset = models.City.objects.all()
    return render(request, "city_list.html", {'queryset': queryset})
相关推荐
engchina3 分钟前
Oracle ADB 导入 BANK_GRAPH 的学习数据
数据库·学习·oracle·graph
qq_2739002315 分钟前
pytorch detach方法介绍
人工智能·pytorch·python
虞书欣的634 分钟前
Python小游戏24——小恐龙躲避游戏
开发语言·python·游戏·小程序·pygame
Komorebi.py38 分钟前
【Linux】-学习笔记03
linux·笔记·学习
FHYAAAX42 分钟前
【机器学习】任务十:从函数分析到机器学习应用与BP神经网络
开发语言·python
PyAIGCMaster1 小时前
python环境中,敏感数据的存储与读取问题解决方案
服务器·前端·python
程序员劝退师_1 小时前
Kafka学习笔记
笔记·学习·kafka
何曾参静谧1 小时前
「Py」模块篇 之 PyAutoGUI库自动化图形用户界面库
运维·python·自动化
帅比九日1 小时前
【HarmonyOS NEXT】实战——登录页面
前端·学习·华为·harmonyos
pumpkin845141 小时前
客户端发送http请求进行流量控制
python·网络协议·http