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,
)
'''
總結:
此類問題可能出現在前端,也可能出現在后端,所以要想在最短的時間內定位出錯誤,就需要仔細分析(比如這個問題,源於文件大小的不同,但是只是有一點點不同,所以需要逆向思維,從數據庫查出數據后,再和前端傳來的數據作比較,這樣就能快速找到問題,是前端的問題了)
'''