美文网首页前端开发
Ajax上传数据与文件与后端Django数据接收——两端引渡数据

Ajax上传数据与文件与后端Django数据接收——两端引渡数据

作者: MessyS | 来源:发表于2019-04-14 13:26 被阅读15次

Ajax上传数据与文件与后端Django数据接收——两端引渡数据协议

日前前言

这两天做管理台,重写了前端后端所有关于管理的页面、功能。每一个管理卡片都通过jq的load()方法异步加载。这样的方式极大的节省了管理台的资源加载过程和时间。

但同时也引出了一些问题,当我想提交POST表单的时候,不能直接加入在html结构中直接加入{% csrf_token %}进行后端验证,这个时候,ajax便又登场了,但由于前端发送的数据和后端接收的数据始终不同—_—!!就跟标题一样,漫长的引渡过程,耗了我整整一天的时间才解决,接下来将详细描述踩坑过程


在这里插入图片描述

一、前端——把表单的架子画出来

在这里插入图片描述
<link rel="stylesheet" href="articlesImportMD.min.css">
<form class="g-body-importMD" action='#' enctype="multipart/form-data" method="post">
    <h2>导入MD</h2>

    <div><h3>分类选择:</h3></div>
    <div><input type="checkbox" name='category' value='2' id='s-category'>Python</div>
    <div><input type="checkbox" name='category' value='3' id='s-category'>Django</div>
    <div><input type="checkbox" name='category' value='4' id='s-category'>JavaScript</div>
    <div><input type="checkbox" name='category' value='5' id='s-category'>Css</div>
    <div><input type="checkbox" name='category' value='6' id='s-category'>Linux</div>
    <div><input type="checkbox" name='category' value='7' id='s-category'>安全</div>
    <div><input type="checkbox" name='category' value='8' id='s-category'>树莓派</div>

    <h3><span>导入MD文件:</span><input type="file" name='htmlF' id='s-htmlF' accept=".html"></h3>
    <h3><span>导入附属图片:</span><input type="file" name='imgF' id='s-imgF' multiple="multiple" accept="image/*"></h3>

    <button type='submit'>发布文章</button>
    <br>
    <div class="g-body-importMD-status" style="display:none"></div>  <!--后面显示状态信息使用--!>
</form>

加以了一些样式过后差不多就是这个样式,这步不用怎么关心,只要有功能就好了


在这里插入图片描述

二、前端——如何通过js获取表单的数据和文件对象

通过ajax发送数据和文件两种东西的话,是不能直接通过$('elm').val()这种方式获取到值的。需要新构造一个FormData然后去继承html中的form

var formDataOld = new FormData($('.g-body-importMD'));      // 继承
// 用get方法获取到htmlF这个FileInput中的值,注意,直接打印FormData是没有数据的
var fileHtml = formDataOld.get('htmlF');    

这里有个特殊情况,MD文件我们只需要获取它的文件内容,如果把他也发送给服务器必定会造成响应速度减慢和资源浪费,怎么办呢?这里再新构建一个FormData,然后一个一个的append进FormData即可

// 自定义的表单
var formData = new FormData();
// 获取用户上传文件的信息(html表单)
var formDataOld = new FormData($('.g-body-importMD'));
var fileHtml = formDataOld.get('htmlF');
// 获取文章分类
$("input:checkbox[name=category]:checked").each(function (i) {
    formData.append('categoryList',$(this).val());   // 若需要对应一个列表,那就for循环append即可
});
// 获取文章标题(获取的是文件名,所以清一下后缀)
var fileTitle = fileHtml.name.replace('.html', '');

// 加入所有附属图片到自构建表单内
var photoFiles = document.getElementById("s-imgF").files;
for(var i=0;i<photoFiles.length;i++){
    formData.append('imgF',photoFiles[i]);
}

// 获取文章内容
var reader = new FileReader();
reader.readAsText(fileHtml, 'UTF-8');
reader.onload = function () {
    var fileContext = this.result;
    // 新数据加入表单
    formData.append('fileTitleH', fileTitle);
    formData.append('fileContextH', fileContext);
};

这一系列的操作过后,我们最终得到的是一个名为formData的表单对象,可通过上一步的formData.get()函数分别获取到categoryListfileTitleHfileContextHimgF这四个键的值,如下图:

在这里插入图片描述



这里看着可能会感觉很乱,怎么就突然冒出来一大堆代码了,心情就跟表情包一样,但是实际上都是些重复的操作,复制到自己的js里执行一下就会恍然大悟的

在这里插入图片描述

三、前端——如何携带建好的表单对象发送给后端Django

只要我们把上一步构建好的formData对象直接加入ajax的data里就可以了,Django在获取的时候会直接解析这个表单

其中有一个小问题,就是Djang的csrf会返回403,详细的解决方法可以参看之前写过的文章Ajax常用方法与后端(Django)通信403的解决方案

<script src="jquery.cookie.js"</script>
$.ajax({
    url: '/addArticleMessy/',
    type: 'POST',
    processData: false, // 不处理数据(必须)
    contentType: false,  // 不设置内容类型(必须)
    headers: {
        "X-CSRFToken": $.cookie('csrftoken')  // Django 403处理
    },
    data: formData,   // 直接填入自定义表单对象
    success: function (data) {    // 请求完成后的处理操作
        $('.g-body-importMD-status').empty();
        $('.g-body-importMD-status').html('<div style="color:#19b955">【' + fileTitle + '】发布成功!</div>');
    },
    error: function () {
        $('.g-body-importMD-status').empty();
        $('.g-body-importMD-status').html('<div style="color:#c9302c">服务器数据处理失败,详情查看服务器日志</div>');
    }
});

四、后端——如何接收到相应数据

这里就不讲url、model文件的设置了,后端相对前端的操作要简便一些。

由于没有什么重要的点,就把整段代码展示出来,这里说一下大概的步骤吧:

  • 使用POST.get()FILEFS.getlist()获取数据和文件对象
  • 判断是否有存储该篇文章的文件夹(防止报系统错误)
  • 存储图片
def addHF(self):
    today_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
    # 获取ajax发来的表单信息
    # 一个键的值如果是一个列表的话,请使用getlist获取,否则返回字节对象,我就在这儿卡了好久...
    category_list = self.POST.getlist('categoryList')       # 分类1/2
    fileTitleH = self.POST.get('fileTitleH')                # 文章标题
    fileContextH = self.POST.get('fileContextH')            # 文章内容
    files = self.FILES.getlist('imgF')                      # 附属图片

    # 信息初始化
    name = fileTitleH                                   # 文章名为文件名

    category2 = ''                                      # 多标签获取与判断
    if len(category_list) == 1:
        category1 = category_list[0]
    else:
        category1 = category_list[0]
        category2 = category_list[1]

    def savePhotos():                        # 附属图片的存储,写成函数方便下面判断文件夹进行调用
        for f in files:                      # 通过图片名进行去重操作
            file_exist = os.path.exists('media/articlePhotos/' + fileTitleH + '/' + f.name)
            if file_exist:
                pass
            else:
                # 这里一定要使用wb方式写入,chunks获取的数据是字节类型
                with open('media/articlePhotos/' + fileTitleH + '/' + f.name,'wb+') as destination:
                    for chunk in f.chunks():
                        destination.write(chunk)
    if not files:                                       # 文件夹存在判断,防止系统错误
        pass
    else:
        dir_exist = os.path.exists(r'media/articlePhotos/' + fileTitleH)
        if dir_exist:
            savePhotos()
        else:
            os.mkdir(r'media/articlePhotos/' + fileTitleH)
            savePhotos()

    # 创建一部分字段并存储
    addHF = Article(name=name, time=today_time, category1_id=category1, category2_id=category2)
    addHF.context = context

    # 存进数据库
    addHF.save()

    return render(self, 'jump/manager_jump.html')

最后

到这里,所有的代码整合测试一下,就有一个简单的文章发布功能了。

后面肯定会完善整个后台管理系统的,如果评论喜欢的人多的话,应该也会出一个相关的教程,谢谢大家!

本文作者: Messy
原文链接:https://www.messys.top/detail/67
版权声明: 本博客所有文章除特别声明外, 均采用 CC BY-NC-SA 4.0 许可协议. 转载请注明出处!

相关文章

网友评论

    本文标题:Ajax上传数据与文件与后端Django数据接收——两端引渡数据

    本文链接:https://www.haomeiwen.com/subject/xaguiqtx.html