主要从以下这些方面依次介绍这次django实战经验:
- 数据处理
- django基本框架搭建
- sqlite3数据库
- Json数据
- Echart树状图
- Jquery 异步刷新
- laydate 日期查询
- 前后端交互
数据处理
从本地文件夹中获得所有源文件,使用pandas进行数据的读取与清洗,得到两个dataframe数据。将这两组Dataframe数据写入sqlite3数据库的两个表格中,并生成Echart tree map所需的json文件。使用spyder调试无误后,封装为自定义模块,为后续django调用做准备。
需要注意的一点是,如果打算通过django直接调用python自定义模块,需要将已经写好的自定义模块放入projectname/myapp/management/commands/文件目录下,已“from .modulefilename import modulename”方法导入本地
Django基本构架搭建
比较基础的django构架搭建方法在此不再重复。
1. models.py 定义数据模型
from django.db import models
class Cleanliness(models.Model):
Index = models.IntegerField(primary_key=True)
Standard = models.CharField(max_length=50)
Nr = models.CharField(max_length=50)
Time = models.DateTimeField()
Result = models.CharField(max_length=20)
class Opllist(models.Model):
Index = models.IntegerField(primary_key=True)
Date = models.DateTimeField()
Findings = models.CharField(max_length=50)
Responsible = models.CharField(max_length=20)
Station = models.CharField(max_length=20)
Category = models.CharField(max_length=10)
Risk = models.CharField(max_length=10)
数据库的写入与覆盖操作是使用如下模块执行的,网上对于这个方法有详细的介绍,其中也说过如果是数据库表格的覆盖操作,不建议使用这个方法的replace进行整体替代,而是推荐使用数据库本身的is_deleted方法进行,目前没有尝试过。但如果使用的是to_sql的replace方法,在models.py定义模型时,必须定义主键primary_key,否则在后期调试过程中,会出现数据无法写入数据库的错误。
db = sqlite3.connect(r"C:\Users\WAY1QIN\Desktop\Usecase\cleanliness VSD\VSD\VSDproject\cleanliness.db")
pd.io.sql.to_sql(df,"myapp_cleanliness",con=db,index=True,if_exists="replace")
print('df-success!')
db.close()
2. urls
url.py文件定义如下
from django.urls import path
from . import views
urlpatterns = [
path('',views.index),
path('frame/',views.frame),
path('time/',views.time),
path('refresh/',views.refresh),
path('opl_chart/',views.opl_chart),
]
3. setting.py
setting.py文件配置,设置DATABASES建立与sqlite3数据库的连接, Static设置确保能够正确引用静态文件。
DEBUG = True
ALLOWED_HOSTS = ['*',]
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
]
ROOT_URLCONF = 'VSDproject.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'cleanliness.db'),
}
}
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static')
]
__4. views.py __
Django直接调用自定义模块,在views.py中进行引用 from .management.commands.duoxiancheng import mainfunction
在处理echart所需的json文件时,并没有根据数据库数据再形成json文件,而是通过自定义模块,对DataFrame数据进行处理,先根据treemap的要求生成字典结构的数据,然后再使用
with open(r'C:\Users\WAY1QIN\Desktop\Usecase\cleanliness VSD\VSD\VSDproject\treedata.json', 'w') as f:
json.dump(tree_data, f)
这样相当于把tree_data文件单独存放在一个指定位置,在views后端调用时,对应如下代码进行读取,然后再传递给前端。
with open(r'C:\Users\WAY1QIN\Desktop\Usecase\cleanliness VSD\VSD\VSDproject\treedata.json', 'r') as f:
tree_data = json.load(f)
from django.shortcuts import render
from django.http import HttpResponse
import os
import json
from .management.commands.duoxiancheng import mainfunction
from .models import Cleanliness
from .models import Opllist
def frame(request):
with open(r'C:\Users\WAY1QIN\Desktop\Usecase\cleanliness VSD\VSD\VSDproject\treedata.json', 'r') as f:
tree_data = json.load(f)
partlist = Cleanliness.objects.all().order_by('-Time')
opl_list = Opllist.objects.all().order_by('-Date')
return render(request,'myapp/frame.html',{'parts':partlist,'opls':opl_list,'treedata':json.dumps(tree_data)})
def refresh(request):
runner = request.POST['select1']
mainfunction(runner)
with open(r'C:\Users\WAY1QIN\Desktop\Usecase\cleanliness VSD\VSD\VSDproject\treedata.json', 'r') as f:
tree_data = json.load(f)
partlist = Cleanliness.objects.all()
return render(request,'myapp/refresh.html',{'parts':partlist,'treedata':json.dumps(tree_data)})
def opl_chart(request):
name = request.POST['select']
opl_list_filter = Opllist.objects.filter(Station = name[2:6]).filter(Category=name[0]).order_by('-Date')
return render(request,'myapp/opl_chart.html',{'opls':opl_list_filter})
sqlite3数据库
sqlite3数据库是django自带的轻量级数据库,对于目前这个案例的使用程度,数据量小,数据库调用简单,sqlite3完全可以胜任,而且在settings.py配置时,也比较简单,在自定义模块中的写入和覆盖操作都比较简单。其语法和mysql差别不大。掌握一个数据库的基本用法后,其它的数据库的基本用法可以类推。
Json数据
Echart treemap需要向前端传递Json格式的数据,在自定义模块中根据树状图结构对需要展示的数据进行结构搭建。具体要求可以查看Echart官方文档。
Echart Tree Map
对于树状图的其它介绍echarts中树形结构图(参数分析)
建议啃官方文档Echart官方文档
下载echarts.min.js文件后,放入static/myapp/js/路径下,在html文件中,使用
后端views配置如下,将json数据得到后,放入tree_data,传入前端。
def refresh(request):
print('run!')
runner = request.POST['select1']
mainfunction(runner)
print(runner)
with open(r'C:\Users\WAY1QIN\Desktop\Usecase\cleanliness VSD\VSD\VSDproject\treedata.json', 'r') as f:
tree_data = json.load(f)
partlist = Cleanliness.objects.all()
return render(request,'myapp/refresh.html',{'parts':partlist,'treedata':json.dumps(tree_data)})
进行引用。
<script type="text/javascript" src="/static/myapp/js/echarts.min.js"></script>
<div id="tree_chart" style="widows: 400px;">
<script type="text/javascript">
var treedata = {{ treedata|safe }}
var myChart=echarts.init(document.getElementById('tree_chart'))
myChart.setOption(option = {
tooltip: {
trigger: 'item',
triggerOn: 'mousemove',
},
series:[
{
type: 'tree',
data: [treedata],
left: '20%',
right: '30%',
top: '5%',
bottom: '20%',
symbol: 'circle',
orient: 'LR',
height:"80%",
expandAndCollapse: true,
initialTreeDepth:3,
label: {
normal: {
position: 'top',
rotate: 0,
verticalAlign: 'middle',
align: 'right',
fontSize: 12,
},
},
symbolSize:12,
leaves: {
label: {
normal: {
position: 'right',
rotate: 0,
verticalAlign: 'middle',
align: 'left',
fontSize: 12,
}
}
},
lineStyle: {
curveness:0.5,
},
itemStyle:{
normal:{
color:function(params){
var colorList = ['green','yellow','red']
return colorList[params.value]
},
borderColor:'black',
},
},
animationDurationUpdate: 750,
}
]
}
);
if(myChart._$handlers.click)
{
myChart._$handlers.click.length = 0;
}
myChart.on('click', function(param) {
var par = [param.data.name,param.data.station]
if(par[0].length>1){
$.ajax({
type:'POST',
url:'/time/',
data:{'select':param.name},
dataType:'text',
success:function(data)
{
$('#table').html(data);
}
})
}
if(par[0].length==1){
var strpar = par.toString()
console.log(strpar)
$.ajax({
type:'POST',
url:'/opl_chart/',
data:{'select':strpar},
dataType:'text',
success:function(data)
{
$('#table1').html(data);
}
})
}
console.log(par)
})
</script>
</div>
Jquery 异步刷新
上面代码中,已经包含异步刷新的过程,相关的其它介绍可以搜以下,文章很多,本例中使用异步刷新之前。也做了一些定义,由于我的目标是点击树状图节点可以触发不同的表格进行异步刷新,这就意味这先得判断要触发哪一个表格,所以,在最开始定义tree图用的json数据时,我就把一个表格信息写入了不同的字典层级中,当点击节点后,拿到节点属性,根据表格信息来做if判断,判断要触发哪一个异步刷新,然后再去调用相关的html文件。并将数据从前端传递给后端。
def opl_chart(request):
name = request.POST['select']
opl_list_filter = Opllist.objects.filter(Station = name[2:6]).filter(Category=name[0]).order_by('-Date')
return render(request,'myapp/opl_chart.html',{'opls':opl_list_filter})
def time(request):
name = request.POST['select']
partlist_filter = Cleanliness.objects.filter(Standard = str(name)).order_by('-Time')
return render(request,'myapp/time.html',{'parts1':partlist_filter})
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
</script>
</head>
<body>
<table id='table1'>
<tr>
<th>Date</th>
<th>Findings</th>
<th>Resp</th>
<th>Station</th>
</tr>
<ul>
{%for opl in opls%}
<tr>
<td>{{opl.Date}}</td>
<td>{{opl.Findings}}</td>
<td>{{opl.Responsible}}</td>
<td>{{opl.Station}}</td>
</tr>
{% endfor %}
</ul>
</table>
</body>
</html>
鼠标所点击的节点属性可以通过下面得到
<script type="text/javascript" src="/static/myapp/js/jquery-3.5.1.min.js"></script>
//使用ajax异步刷新表格数据,通过click事件,触发刷新
myChart.on('click', function(param){}
如果异步刷新出现权限问题时,记得在要刷新的语句前加上
$.ajaxSetup({
data:{csrfmiddlewaretoken:'{{ csrf_token }}'}
})
laydate 日期查询
下载laydate.js, 放在static/laydate目录下,并使用异步刷新,这样在选中日期后,将选择的日期以POST的形式传给后端,并对整个页面进行刷新。
<script>
function getdata(){
var text = document.getElementById("test1");
console.log(text.value)
$.ajax({
type:'POST',
url:'/refresh/',
data:{'select1':text.value},
dataType:'text',
success:function(data){
$('box').html(data)
}
})
}
$.ajaxSetup({
data:{csrfmiddlewaretoken:'{{ csrf_token }}'}
})
</script>
<input type="text" id='test1'>
<button id='btn' onclick="getdata()">Search</button>
<script src="/static/laydate/laydate.js"></script>
<script>
laydate.render({
elem:'#test1',
range:true,
});
</script>
效果如下:
前后端交互
前后端交互的大部分方法都可以搜过相关文章找到,关于自定义模块的刷新,可以在views.py中引入自定义模块执行语句,来进行刷新,也可以在前端设置button,将button触发指令传递给后端,来调用自定义模块。表格和tree图的交互,主要是组合数据库的查询指令实现的,将所有数据清洗写入数据库后,可以实现快速刷新,而且不必再次执行自定义模块,可以加快程序运行。
断断续续的写了这个程序,最终也没有正式使用,但在这个过程中,自己是对django进行了一次实践,学习到了不少东西。第一次搭建,难免会有很多不是最优的地方,但至少功能是实现了。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)