通过Django的form及Ajax等多种方式上传文件

如下效果:

方式一、通过Django的Form方式上传文件

思路:前台html创建Form,根据格式要求完善form内标签属性;提交后台后,后台获取前台传来的数据进行处理:文件路径保存至数据库,文件内容保存至本地文件夹中;后台处理完成后刷新前台页面。

1、创建空白Django项目,过程忽略。

2、静态html页面设置:

<form action="/upload.html" method="post" enctype="multipart/form-data">
    <input type="text" name="fileName">
    <input type="file" name="fileContent">
    <input type="submit" value="提交">
</form>

写一个form表单,三个关键标签:text、file、submit,分别存新的文件名、文件内容、提交按钮,由于是文件上传因此form中enctype需要设置成multipart/form-data。

3、views后台设置:

from django.shortcuts import render,redirect
import os

def Upload(request):
   if request.method=="GET":
      
        return render(request,"upload.html")
    elif request.method=="POST":
        # 获取普通input标签值,即文件名
        filname=request.POST.get('fileName')
        # 获取file类型的input标签值,即文件内容
        file=request.FILES.get('fileContent')

        # 获取文件后缀名
        postfix=file.name.split('.')[1]
        # 设置本地文件路径
        file_path=os.path.join('static',filname+'.'+postfix)


        # 将上传的文件写入本地目录
        f=open(file_path,"wb")
        for chunk in file.chunks():
            f.write(chunk)
        f.close()


        return redirect("upload.html")

url文件配置:

from Upload import views

urlpatterns = [
   
    path('upload.html',views.Upload),
]

原理:

(1)、当Get请求时,即浏览器打开该网页时,显示上传页面;

(2)、当POST请求时,即点击“提交”按钮时:

①、获取界面传过来的新的文件名及文件内容。

②、分块读取文件内容,并写入到本地目录。

4、页面上动态显示刚刚上传的图片,需做如下改造:

(1)、新建数据库表,用来存储图片路径:

# 图片类
class image(models.Model):
    # 路径
    file_Path=models.CharField(max_length=32)

(2)、在上传成功时将文件路径保存至数据库,即在views的视图方法的POST中的保存文件后面添加代码:

   # 写入成功后将路径保存至数据库
        models.image.objects.create(file_Path=file_path)

(3)、页面刷新时展现图片,即在视图方法的GET中读取数据库中添加的图片路径,并将其返给html页面:

 if request.method=="GET":
        # 获取所有图片
        imgs=models.image.objects.all()
        return render(request,"upload.html",{"imgs":imgs})

(4)、html页面中增加

<div class="imgs">
    {% for obj in imgs %}
         <img src="{{ obj.file_Path }}">
    {% endfor %}
</div>

(5)、由于Django对静态文件浏览的限制,需要在配置中添加:

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR,"static"),
]

方式二、通过原生js实现

思路:html页面,通过FormData承载图片内容,并通过原生的XMLHttpRequest将页面全部信息传输到后台views中;后台views接收后处理并将结果通过json形式返回给前台html页面;前台html页面接收到字符串内容后转换为json对象;创建图片标签,并将接收到的图片地址赋值。

1、url配置如下:

from Upload import views

urlpatterns = [
   
    path('uploadjs.html', views.Upload_js),

]

2、views视图函数:

def Upload_js(request):
    if request.method == "GET":
        # 获取所有图片
        imgs = models.image.objects.all()
        return render(request, "upload_js.html", {"imgs": imgs})
    elif request.method == "POST":
        # 获取普通input标签值,即文件名
        filname = request.POST.get('fileName')
        # 获取file类型的input标签值,即文件内容
        file = request.FILES.get('fileContent')

        # 获取文件后缀名
        postfix = file.name.split('.')[1]
        # 设置本地文件路径
        file_path = os.path.join('static', filname + '.' + postfix)

        # 将上传的文件写入本地目录
        f = open(file_path, "wb")
        for chunk in file.chunks():
            f.write(chunk)
        f.close()

        # 写入成功后将路径保存至数据库
        models.image.objects.create(file_Path=file_path)

        #将状态及文件路径通过json形式返回至html页面
        ret={'status':True,'path':file_path}
        return HttpResponse(json.dumps(ret))

3、前台html页面

<body>

    <input type="text" name="fileName" id="fileName">
    <input type="file" name="fileContent" id="fileContent">
    <input type="button" value="提交" onclick="upload();">

<div class="imgs">
    {% for obj in imgs %}
         <img src="{{ obj.file_Path }}">
    {% endfor %}
</div>

<script>
    function upload() {
        //创建FormData用于存储文件内容
        var dict=new FormData();
        dict.append("fileName",document.getElementById('fileName').value);
        dict.append("fileContent",document.getElementById('fileContent').files[0]);


        var xml=new XMLHttpRequest();
        //uploadjs.html即url.py中配置的后台views
        xml.open("post",'/uploadjs.html',true);
        xml.onreadystatechange=function(){
            if (xml.readyState==4 && xml.status==200) {
                //传输成功时将视图返回回来的内容通过json接收
                var obj=JSON.parse(xml.responseText);
                if(obj.status){
                    //创建图片标签,并将后台传回来的图片地址加上,显示在页面中
                    var img=document.createElement('img');
                    img.src='/'+obj.path;
                    document.getElementsByClassName('imgs')[0].appendChild(img);
                }
            }
        };

        xml.send(dict)
    }
</script>
</body>

 

 


方式三、通过JQuery实现

原理:将方式二中原生js部分改为JQuery形式,其他无变化。

html页面代码如下:

<body>

    <input type="text" name="fileName" id="fileName">
    <input type="file" name="fileContent" id="fileContent">
    <input type="button" value="提交" onclick="upload();">

<div class="imgs">
    {% for obj in imgs %}
         <img src="{{ obj.file_Path }}">
    {% endfor %}
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
    function upload() {
        //创建FormData用于存储文件内容
        var dict=new FormData();
        dict.append("fileName",document.getElementById('fileName').value);
        dict.append("fileContent",document.getElementById('fileContent').files[0]);


      $.ajax({
          url:'/uploadjq.html',
          type:'post',
          data:dict,
          processData: false,// 告诉jQuery不要去处理发送的数据(必须设置)
      contentType: false, // 告诉jQuery不要去设置Content-Type请求头(必须设置)
          dataType:'JSON',
          success:function (arg) {
            if(arg.status){
               //创建图片标签,并将后台传回来的图片地址加上,显示在页面中
                    var img=document.createElement('img');
                    img.src='/'+arg.path;
                    $('.imgs')[0].appendChild(img);
            }
          }
      })
    }
</script>
</body>

注意:由于使用的是FormData对象,需要将processData、contentType设置成false,至于为什么要这么设置,详见:

[#1] 浅谈contentType = false 
[#2] 原生ajax请求 怎么设置processData这个参数? 

 


方式四、通过iframe及form表单,views后台代码与方式二一致

原理:将views后台返回的数据传给iframe页面标签,触发iframe的onload事件时实现img图片动态加载。

1、原生js时,获取iframe对象内容通过document.getElementById('iframe的ID').contentWindow.document.getElementById('元素的ID');contentWindow代表frameiframe内部的窗口对象。html前台页面如下:

<body>
<form action="/uploadiframe.html" method="post" enctype="multipart/form-data" target="img_igrame">
    <iframe id="img_igrame" name="img_igrame" onload="loadiframe(this)"  ></iframe>
    <input type="text" name="fileName">
    <input type="file" name="fileContent">
    <input type="submit" value="提交">
</form>
<div class="imgs">
    {% for obj in imgs %}
         <img src="{{ obj.file_Path }}">
    {% endfor %}
</div>

<script>

    function loadiframe(self) {

            // 获取iframe内部的内容
           var str_json=self.contentWindow.document.getElementsByTagName('body')[0].innerText;
            var obj = JSON.parse(str_json);
            if (obj.status){
                var img = document.createElement('img');
                img.src = "/" + obj.path;
                document.getElementsByClassName('imgs')[0].appendChild(img);
               
            }

    }
</script>

</body>

 参考:JS获取/设置iframe内对象元素、文档的几种方法

2、jQuery时,通过.contents() 方法;.contents() 方法允许我们检索 DOM 树中的这些元素的直接子节点,并用匹配元素构造新的 jQuery 对象。.contents() 和 .children() 方法类似,不同的是前者在结果 jQuery 对象中包含了文本节点以及 HTML 元素。.contents() 方法也可以用于获得 iframe 的内容文档,前提是该 iframe 与主页面在同一个域。代码如下:

<body>
<form action="/uploadiframe.html" method="post" enctype="multipart/form-data" target="img_igrame">
    <iframe id="img_igrame" name="img_igrame" onload="loadiframe(this)"  ></iframe>
    <input type="text" name="fileName">
    <input type="file" name="fileContent">
    <input type="submit" value="提交">
</form>
<div class="imgs">
    {% for obj in imgs %}
         <img src="{{ obj.file_Path }}">
    {% endfor %}
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>

    function loadiframe(self) {

            // 获取iframe内部的内容
            var str_json = $('#img_igrame').contents().find('body').text();

    
            var obj = JSON.parse(str_json);
            if (obj.status){
                var img = document.createElement('img');
                img.src = "/" + obj.path;
                $('#imgs').append(img);
             
            }

    }
</script>

</body>

参考:Js/Jquery获取iframe中的元素

=======

总结:

通过Django的Form方式上传文件,简单,但无法局部刷新实现ajax效果;

通过js或jQuery方式,需要使用FormData对象,仍有些浏览器不兼容;

通过Form+iframe方式上传文件,兼容性最好。

 

完整源代码请见:https://download.csdn.net/download/baobao267/10718732

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将Django模型表单渲染成Dropzone风格的上传文件表单,您可以使用第三方库或自定义方法。以下是其中两种常见的实现方式: 1. 使用第三方库:可以使用现有的第三方库来轻松地将Django模型表单渲染成Dropzone风格的上传文件表单。一个流行的库是`django-dropzone`。以下是使用`django-dropzone`的示例: - 安装`django-dropzone`库: ``` pip install django-dropzone ``` - 在您的Django项目的`settings.py`文件中添加`dropzone`到`INSTALLED_APPS`: ```python INSTALLED_APPS = [ # 其他应用... 'dropzone', ] ``` - 在您的模板文件中,使用`{{ form.media }}`来加载所需的CSS和JavaScript文件。 - 在您的模板文件中,使用`{{ form|dropzone }}`来渲染Dropzone风格的上传文件表单。 ```html <form method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form|dropzone }} <input type="submit" value="上传"> </form> ``` 2. 自定义实现:如果您想自定义实现Dropzone风格的上传文件表单,可以使用Dropzone的JavaScript库来构建表单。以下是一个基本的自定义实现示例: - 在您的模板文件中,加载Dropzone的CSS和JavaScript文件。 ```html <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/min/dropzone.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.2/min/dropzone.min.js"></script> ``` - 创建一个表单元素,并为其添加一个ID。此ID将在后面的JavaScript代码中使用。 ```html <form method="post" enctype="multipart/form-data" action="{% url 'upload' %}" id="my-dropzone" class="dropzone"> {% csrf_token %} <div class="fallback"> <input type="file" name="file" multiple> <input type="submit" value="上传"> </div> </form> ``` - 添加JavaScript代码,初始化Dropzone实例并配置参数。 ```javascript <script> Dropzone.autoDiscover = false; $(function() { // 初始化Dropzone实例 var myDropzone = new Dropzone("#my-dropzone", { url: "{% url 'upload' %}", paramName: "file", // 与模型表单中的文件字段名称相匹配 maxFilesize: 10, // 最大文件大小限制(单位:MB) addRemoveLinks: true, // 显示删除链接 acceptedFiles: ".jpg,.jpeg,.png,.gif", // 允许上传的文件类型 // 其他自定义配置... }); }); </script> ``` - 在视图函数中处理上传文件的逻辑,与之前的代码示例类似。 上述两种方法都可以将Django模型表单渲染成Dropzone风格的上传文件表单。您可以根据个人偏好和项目需求选择适合您的方法。 希望这些信息对您有所帮助!如果您还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值