js 上传文件,通过django存储到数据库,保存类型为blob类型

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">&times;</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类型

上一篇:SQL语法基础之create


下一篇:MySql查询数据