数据统计图表 && 文件上传
1. 图表
- highchart【国外】
- echarts【国内百度开源】 √
引入echarts
<script src="{% static 'js/echarts.js' %}"></script>
1.1 柱状图
<div class="row">
<div class="col-sm-8">
<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>
/**
* 初始化柱状图
*/
function initBar() {
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById("m2"));
// 指定图表的配置项和数据
var option = {
title: {
text: "员工上半年业绩月度汇总信息",
// subtext: "广州车陂公司",
textAlign: "auto",
left: "center",
},
tooltip: {},
legend: {
data: [], // 后台获取
bottom: 0,
},
xAxis: {
data: [], // 后台获取
},
yAxis: {},
series: [], // 后台获取
};
$.ajax({
url: "/chart/bar",
type: "get",
dataType: "JSON",
success: function (res) {
// 将后台返回的数据,更新到option中
if (res.status) {
option.legend.data = res.data.legend;
option.xAxis.data = res.data.x_axis;
option.series = res.data.series_list;
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
},
});
}
""" 构造柱状图的数据 """
def chart_bar(request):
# 数据可以去数据库中获取,目前写死
legend = ["徐泽林", "郭梦茹"]
series_list = [
{
"name": "徐泽林",
"type": "bar",
"data": [5, 20, 36, 10, 10, 20],
},
{
"name": "郭梦茹",
"type": "bar",
"data": [20, 10, 56, 2, 19, 41],
},
]
x_axis = ["1月","2月","3月","4月","5月","6月"]
result = {
"status": True,
"data": {
"legend": legend,
"series_list": series_list,
"x_axis": x_axis
}
}
return JsonResponse(result)
1.2 饼状图
<div class="col-sm-5">
<div class="panel panel-default">
<div class="panel-heading">饼图</div>
<div class="panel-body">
<div id="m3" style="width: 100%; height: 400px"></div>
</div>
</div>
</div>
/**
* 初始化饼状图
*/
function initPie() {
var myChart = echarts.init(document.getElementById("m3"));
var option = {
title: {
text: "部门预算占比",
subtext: "棠东分公司",
left: "center",
},
tooltip: {
trigger: "item",
},
legend: {
bottom: 0,
},
series: [
{
name: "预算",
type: "pie",
radius: "50%",
data: [],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)",
},
},
},
],
};
$.ajax({
url: "/chart/pie/",
type: "get",
dataType: "JSON",
success: function (res) {
if (res.status) {
option.series[0].data = res.data;
myChart.setOption(option);
}
},
});
}
""" 构造饼图的数据 """
def chart_pie(request):
result = {
"status": True,
"data": [
{ "value": 1048, "name": "IT部门" },
{ "value": 735, "name": "运营部门" },
{ "value": 4580, "name": "新媒体部门" },
{ "value": 484, "name": "产品部门" },
]
}
return JsonResponse(result)
1.3 折线图
<div class="panel panel-default">
<div class="panel-heading">折线图</div>
<div class="panel-body">
<div id="m1" style="width: 100%; height: 260px"></div>
</div>
</div>
/**
* 初始化折线图
*/
function initLine() {
var myChart = echarts.init(document.getElementById("m1"));
var option = {
title: {
text: "分公司上半年业绩图",
left: "center",
},
tooltip: {
trigger: "axis",
},
legend: {
data: [],
bottom: 0,
},
toolbox: {
feature: {
saveAsImage: {},
},
},
xAxis: {
type: "category",
boundaryGap: false,
data: [],
},
yAxis: {
type: "value",
},
series: [],
};
$.ajax({
url: "/chart/line/",
type: "get",
dataType: "JSON",
success: function (res) {
if (res.status) {
option.legend.data = res.data.legend;
option.xAxis.data = res.data.x_axis;
option.series = res.data.series_list;
myChart.setOption(option);
}
},
});
}
""" 构造折线图的数据 """
def chart_line(request):
legend = ["车陂分公司", "棠东分公司"]
x_axis = ["1月", "2月", "3月", "4月", "5月", "6月"]
series_list = [
{
"name": "车陂分公司",
"type": "line",
"stack": "Total",
"data": [120, 132, 101, 134, 90, 230],
},
{
"name": "棠东分公司",
"type": "line",
"stack": "Total",
"data": [220, 182, 191, 234, 290, 330],
}
]
result = {
"status": True,
"data": {
"legend": legend,
"x_axis": x_axis,
"series_list": series_list
}
}
return JsonResponse(result)
2. 关于文件上传
2.1 基本操作
from django.shortcuts import render,HttpResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def upload_list(request):
if request.method == 'GET':
return render(request,'upload_list.html')
# print(request.POST) # 请求体中的数据
# print(request.FILES) # 请求发过来的文件
file_object = request.FILES.get('avatar')
# print(file_object.name) # 上传过来的文件名
f = open(file_object.name,'wb')
for chunk in file_object.chunks():
f.write(chunk)
f.close()
return HttpResponse("...")
<form action="#" method="post" enctype="multipart/form-data">
<input type="text" name="username">
<input type="file" name="avatar">
<input type="submit" value="提交">
</form>
案例:批量上传数据
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-list" aria-hidden="true"></span>
批量上传
</div>
<div class="panel-body">
<form action="/depart/multi/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<input type="file" name="exc" />
</div>
<input type="submit" value="上传" class="btn btn-info btn-sm" />
</form>
</div>
</div>
"""
文件上传案例(上传Excel文件-批量添加数据)
"""
def depart_multi(request):
# 1. 获取用户上传的文件对象
file_object = request.FILES.get("exc")
print(type(file_object))
# 2. 对象传递给openpyxl,由openpyxl读取文件的内容
wb = load_workbook(file_object)
sheet = wb.worksheets[0]
# 3. 循环获取每一行的数据
for row in sheet.iter_rows(min_row=2):
text = row[0].value
exists = models.Department.objects.filter(title=text).exists()
if not exists:
models.Department.objects.create(title=text)
return redirect('/depart/list/')
案例:混合数据提交(Form)
提交页面时:用户输入数据 + 多个文件字段(输入不能为空、规范输入报错…)
- Form生成HTML标签:type = file
- 表单的验证
- form.cleaned_data获取 数据+文件对象
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{ title }}</h3>
</div>
<div class="panel-body">
<form method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %} {% for field in form %}
{{ field }}
{{ field.errors.0 }}
{% endfor %}
<button type="submit" class="btn btn-primary">提 交</button>
</form>
</div>
</div>
</div>
class UpForm(BootStrapForm):
bootstrap_exclude_fields = ["img"]
name = forms.CharField(label="姓名")
age = forms.IntegerField(label="年龄")
img = forms.FileField(label="头像")
def upload_form(request):
title = "Form上传"
if request.method == "GET":
form = UpForm()
return render(request,'upload_form.html', {"form":form, "title": title})
form = UpForm(data=request.POST, files=request.FILES)
if form.is_valid():
# print(form.cleaned_data)
# form.save()
# 1. 读取图片内容,写入到文件夹中并获取文件的路径
image_object = form.cleaned_data.get("img")
# file_path = "app01/static/img/{}".format(image_object.name)
db_file_path = os.path.join("static", "img", image_object.name)
file_path = os.path.join("app01", db_file_path)
f = open(file_path, mode='wb')
for chunk in image_object.chunks():
f.write(chunk)
f.close()
# 2. 将文件路径写入数据库
models.Boss.objects.create(
name=form.cleaned_data["name"],
age=form.cleaned_data["age"],
img=db_file_path
)
return render(request, 'upload_form.html', {"form": form, "title": title})
return render(request,'upload_form.html', {"form":form, "title": title})
就目前而言,所有的静态文件都只能放在static目录
- 在Django的开发过程中两个特殊的文件夹
- static,存放静态文件的路径,包括CSS、JS、项目所需要用到的图片
- media,用户上传的数据
2.2 启用media目录
- 在urls.py中进行配置:
from django.urls import path,re_path
from django.views.static import serve
from django.conf import settings
urlpatterns = [
# path('admin/', admin.site.urls),
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/"
- 在根目录创建media文件夹
- 在浏览器中访问:http://127.0.0.1:8000/media/7af926c0bb31957baa5cb4b882b0f2f.jpg
案例:混合数据(FORM修改版)
def upload_form(request):
title = "Form上传"
if request.method == "GET":
form = UpForm()
return render(request,'upload_form.html', {"form":form, "title": title})
form = UpForm(data=request.POST, files=request.FILES)
if form.is_valid():
# print(form.cleaned_data)
# form.save()
# 1. 读取图片内容,写入到文件夹中并获取文件的路径
image_object = form.cleaned_data.get("img")
# file_path = "app01/static/img/{}".format(image_object.name)
# media_path = os.path.join(settings.MEDIA_ROOT, image_object.name)
media_path = os.path.join("media", image_object.name)
f = open(media_path, mode='wb')
for chunk in image_object.chunks():
f.write(chunk)
f.close()
# 2. 将文件路径写入数据库
models.Boss.objects.create(
name=form.cleaned_data["name"],
age=form.cleaned_data["age"],
img=media_path
)
return render(request, 'upload_form.html', {"form": form, "title": title})
return render(request,'upload_form.html', {"form":form, "title": title})
案例:混合数据(ModalForm)
- models.py
""" 城市表"""
class City(models.Model):
name = models.CharField(verbose_name="名称", max_length=32)
count = models.IntegerField(verbose_name="人口")
# 本质上数据库也是CharField,自动保存数据
img = models.FileField(verbose_name="LOGO", max_length=128, upload_to="city/")
- 定义ModelForm
class UpModelForm(BootStrapModelForm):
bootstrap_exclude_fields = ['img']
class Meta:
model = models.City
fields = "__all__"
""" ModelForm上传文件和数据 """
def upload_modalform(request):
if request.method == "GET":
form = UpModelForm()
return render(request,'upload_form.html', {"form": form, "title": "ModelForm上传"})
- 视图
""" ModelForm上传文件和数据 """
def upload_modalform(request):
if request.method == "GET":
form = UpModelForm()
return render(request,'upload_form.html', {"form": form, "title": "ModelForm上传"})
form = UpModelForm(data=request.POST, files=request.FILES)
if form.is_valid():
# 对于文件,自动保存
# 字段+上传路径写入到数据库
form.save()
return render(request, 'upload_form.html', {"form": form, "title": "ModelForm上传"})
return render(request, 'upload_form.html', {"form": form, "title": "ModelForm上传"})
2.3 小结
- 自动手动去写(部门管理)
- Form上传
- ModelForm上传
from django.shortcuts import render,HttpResponse,redirect
from app01 import models
from app01.utils.bootstrap import BootStrapModelForm
def city_list(request):
queryset = models.City.objects.all()
return render(request,'city_list.html', {'queryset':queryset})
class UpModelForm(BootStrapModelForm):
bootstrap_exclude_fields = ['img']
class Meta:
model = models.City
fields = "__all__"
def city_add(request):
if request.method == "GET":
form = UpModelForm()
return render(request,'upload_form.html', {"form": form, "title": "新建城市"})
form = UpModelForm(data=request.POST, files=request.FILES)
if form.is_valid():
# 对于文件,自动保存
# 字段+上传路径写入到数据库
form.save()
return redirect("/city/list")
return render(request, 'upload_form.html', {"form": form, "title": "新建城市"})
<div class="container">
<div style="margin-bottom: 20px">
<a href="/city/add/" class="btn btn-success">
<span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
新建城市
</a>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-list" aria-hidden="true"></span>
城市列表
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>LOGO</th>
<th>名称</th>
<th>人口</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
{{ obj.id }}
{{ obj.name }}
{{ obj.count }}
{% endfor %}
</tbody>
</table>
</div>
<ul class="pagination">
{{ page_string }}
</ul>
</div>