1.图表Echarts的应用
Apache ECharts
1.1 使用方法
引用echarts.js即可到官方文档中查询使用
1.2 常用图标的使用
图表展示页面的部署(主要展示折线图、柱状图、饼图)
{% 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的标签,展示折线图
<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视图函数
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的各个属性进行赋值
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的标签,展示柱状图
<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视图函数
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的各个属性进行赋值
option.legend.data = res.data.legend; option.xAxis.data = res.data.x_data; option.series = res.data.series;
1.2.2 饼状图
- 官方文档代码
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的标签,展示饼状图
<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视图函数
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的各个属性进行赋值
option.series[0].data = res.data;
2.文件的上传
2.1 基础操作
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>
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
返回所有文件组成的数据对象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的文件# 由于文件在内存一块一块的存储,利用循环遍历每一块,写入f中 for chunk in file_object.chunks(): # chunks()读取文件对象的内容 f.write(chunk) f.close()
选择上传的图片后,点击提交按钮,图片会以post的方式传入视图函数,通过file_object = request.FILES['photo']
获取文件对象,并且chunks()读取文件对象的内容,最终将图片下载到项目目录中
2.2通过文件批量上传数据
将excel中存在部门批量添加到部门列表中
部门页面增加批量上传按钮
<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>
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
中配置
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
中配置
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
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定义
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
{% 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()
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
{% 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()的视图函数
def city_list(request):
queryset = models.City.objects.all()
return render(request, "city_list.html", {'queryset': queryset})