js 上传文件,通过django存储到数据库,保存类型为blob类型
"""
整体思路:
前端通过input框上传文件,然后通过reader读取文件,jq发送post请求到后台 ,后台通过orm存储到数据库blob文件
"""
‘‘‘
思考的几个坑点:
代码写完后,测试出现前端上传和数据库上传的文件大小不一致的问题,解决过程中有以下几个思路:
1.数据库存储的是blob类型,但是django model并没有对应的类型,所以猜测可能数据格式转换的差异导致的大小不一
答:通过数据库反向生成model得出Blob类型对应的是text类型,所以类型方面应该没有问题,此外,django直接用orm语句操作,类型转换方面也没有乱码,所以猜测不应该是后台的问题。(通过先读取数据库,拿到blob数据,看一下和我传过去的数据有什么区别,结果发现是少了一些换行符\r\n)
2.猜测是前端上传数据的大小就不对。
答:通过查询得到上传文件直接val()取到的是文件路径,而不是文件的内容,然后找到读取文件的方法,声明一个reader对象,然后把文件传进去进行读取,在read.onload中接收数据;
在前端直接打印读取的文件时,发现大小并没有变化,所以上传的文件是没有问题的,但是因为一开始没想到read.onload里文件读取的值怎么传到sub提交函数中,所以用了老办法(就是将值先传给一个display:none的标签,然后再用选择器取值)
问题就出现在这里,因为赋值给标签,之后再取值会发现格式乱掉了,该有的\r\n换行,都没有了,所以就想办法生成一个全局变量,用于存放上传的文件(注意,上传文件是在input的监听事件里,一有文件上传,就需要把值赋给全局变量),然后再把数据发给后台,就可以了。
‘‘‘
‘‘‘具体代码如下‘‘‘
paper.html
{#上传策略模态框#}
<div class="modal fade" data-backdrop="static" id="upmodal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" style="width: 450px;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span></button>
<h4 class="modal-title">上传策略</h4>
</div>
<div class="modal-body" style="padding: 30px;height:auto">
<form>
<div style="margin-top:3%; display: block">
<label>策略名称</label>
<input class="opts form-control" id="stgname" name="stgname" type="text"
placeholder="策略名称">
</div>
<div style="margin-top:3%"><label>指定服务器</label>
<select class="opts form-control" id="envname" name="envname">
<option value="">-</option>
{% for env in envs_obj %}
{% if env.type == ‘1‘ %}
<option name="envname" value="{{ env.envid }}">
{{ env.envname }}
</option>
{% endif %}
{% endfor %}
</select>
</div>
<div style="margin-top:3%"><label>策略组</label>
<select class="opts form-control" id="stggroup" name="stggroup">
<option value="">-</option>
<option name="isactive" value="1">
做市策略
</option>
<option name="isactive" value="2">
CTA策略
</option>
<option name="isactive" value="3">
算法策略
</option>
</select>
</div>
<div style="margin-top:3%"><label>选择文件</label>
<input class="opts form-control" id="file" name="file" type="file" accept=".py"
placeholder="选择文件" onchange="filename1()">
</div>
<div style="margin-top:3%"><label>策略参数</label>
<table style="background-color: white">
<thead>
<tr class="activetable">
<th>
操作
</th>
<th>
参数名*
</th>
<th>
参数值*
</th>
<th>
参数描述
</th>
</tr>
</thead>
<tbody id="tb1">
<tr class="activetable">
<td>
<span style="padding:3px;cursor: pointer" class="btn-success small"
onclick="new_col(‘tb1‘)">新增行
</span>
</td>
<td>
<input class="activetable" name="stg_name" id="stg_name">
</td>
<td>
<input class="activetable" name="stg_value" id="stg_value">
</td>
<td>
<input class="activetable" name="stg_desc" id="stg_desc">
</td>
</tr>
</tbody>
</table>
</div>
<div style="margin-top:3%">
<span style="margin-left:10%;cursor:pointer;padding:5px" class="btn-primary"
onclick="sub(gets)">提交</span>
<span style="margin-left:60%;cursor:pointer;padding:5px" class="btn-success"
onclick="fad_upmodeal_add_change()">取消</span>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- js部分--->
<script type="text/javascript">
//上传策略模态框input框的值,
function gets() {
//仿真策略参数表的条数[{key,value,desc},{}]
var pararry = []
$("#tb1").find("tr").each(function () {
var tdata = $(this).children()
var paraname = tdata.eq(1).find("input").val()
var paravalue = tdata.eq(2).find("input").val()
var paradesc = tdata.eq(3).find("input").val()
var paradic = {"paraname": paraname, "paravalue": paravalue, "paradesc": paradesc}
pararry.push(paradic)
})
data = {
‘stgname‘: JSON.stringify([$(‘#stgname‘).val()]),
‘envname‘: JSON.stringify([$(‘#envname‘).val()]),
‘stggroup‘: JSON.stringify([$(‘#stggroup‘).val()]),
{#‘file‘: JSON.stringify([file]),#}
‘pararry‘: JSON.stringify(pararry)
}
return data;
}
//上传策略提交逻辑
function sub(func) {
data = func();
data[‘file‘] = JSON.stringify([files])
{#console.log("xxxxxxxxxxx", files)#}
//对提交的数据进行遍历,json解析成数组取第一个值,然后取Bool值,
// 如果是false(空),则alert,并且返回空,不继续执行下面代码
for (let key in data) {
var item = JSON.parse(data[key])[0]
if (Boolean(item) == false && key != ‘id‘) {
var title = $("#" + key).prev().text()
alert(title + "不能为空!")
return
}
}
$.post("{% url ‘trade:paper‘ %}", data, function (r) {
if (r == ‘y‘) {
//新建成功则跳转,否则传错误信息
window.location.reload();
} else {
window.location.reload();
}
});
}
//全局变量,用于取得上传的文件
var files = ""
//只能上传py文件
function filename1() {
var filename_ = $("#file").val()
{#var file = $("#file").files[0]#}
if (filename_ && filename_.slice(-3) != ".py") {
alert("请上传py为后缀的文件!")
$("#file").val("")
}
//文件上传(文件读取)
const file = document.getElementById("file").files[0];
{#console.log("file", file)#}
if (file) {
{#console.log("234")#}
var reader = new FileReader();
{#reader.readAsBinaryString(file);#} //乱码
{#reader.readAsDataURL(file); //需要base64解码,然后再解码(会有16进制的数据)#}
reader.readAsText(file, "utf-8"); //大小不一致
reader.onload = function () {
var file_ = reader.result
files = file_
{#console.log("files", file_)#}
if (file_){
{#console.log(file_)#}
return file_
}
}
}
}
</script>
paper.py
‘‘‘
基于web自动生成的策略编号赋值,
算法策略以50001开始递增,其他策略以10001开始递增
Strategy_ID = 10001
‘‘‘
# 上传策略,写入策略表,仿真策略审批表,仿真策略参数表
data = request.POST
stggroup_other = 10001
stggroup_sf = 50001
stggroup_3 = Strategy.objects.filter(stggroup=‘3‘).aggregate(Max(‘stgid‘))
stggroup_1_2 = Strategy.objects.exclude(stggroup=‘3‘).aggregate(Max(‘stgid‘))
if json.loads(data[‘stggroup‘])[0] == ‘3‘:
# 算法策略组
if stggroup_3[‘stgid__max‘]:
stgid = stggroup_3[‘stgid__max‘] + 1
else:
stgid = stggroup_sf
else:
# 非算法策略组
if stggroup_1_2[‘stgid__max‘]:
stgid = stggroup_1_2[‘stgid__max‘] + 1 # int + int
else:
stgid = stggroup_other
filt = json.loads(data["file"])[0]
# print("这是前端传来的文件", filt )
# print(type(filt))
# 新增 策略表
createtime = chardate()
# x = Strategy.objects.values("stgfile").filter(stgid=10040)
# print(x)
Strategy.objects.create(
stgid=stgid,
stgname=json.loads(data["stgname"])[0],
stggroup=json.loads(data["stggroup"])[0],
stgfile=filt,
createtime=createtime,
backupdatetime=chardate(),
customerid=request.session.get(‘customerid‘, ‘‘),
backtest=-1,
status=‘‘,
paperisdelete=1,
liveisdelete=1,
)
‘‘‘
总结:
此类问题可能出现在前端,也可能出现在后端,所以要想在最短的时间内定位出错误,就需要仔细分析(比如这个问题,源于文件大小的不同,但是只是有一点点不同,所以需要逆向思维,从数据库查出数据后,再和前端传来的数据作比较,这样就能快速找到问题,是前端的问题了)
‘‘‘
js 上传文件,通过django存储到数据库,保存类型为blob类型