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 settingsurlpatterns = [re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),]
settings.py
中配置
import osMEDIA_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,但是本质上还是charFieldimg = 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.Cityfields = ['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.pngform.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})