Django文件上传实战:本地存储、数据库路径与AJAX异步处理

闻溪
闻溪
发布时间:2026-10-13| 6人浏览过
原创

本文详解Django中实现文件上传的多种方案,涵盖本地服务器存储、数据库路径管理及AJAX异步提交。重点解析Form表单与AJAX在ContentType指定上的差异,包括enctype属性、processData与contentType参数设置,以及MEDIA_ROOT与MEDIA_URL的配置方法,确保文件可被正确访问。

1 将文件保存到服务器本地

upload.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
  {% csrf_token %}
  <div>用户名:<input type="text" name="username"></div>
  <div>头像<input type="file" name="avatar"></div>
  <input type="submit" value="提交">
</form>
</body>
</html>

urls.py

from django.conf.urls import url
from app01 import views
urlpatterns = [
  url(r'^upload',views.upload)
]

views.py

from django.shortcuts import render,HttpResponse 
def upload(request):
  if request.method == 'POST':
    name = request.POST.get('username')
    avatar = request.FILES.get('avatar')
    with open(avatar.name,'wb') as f:
      for line in avatar:
        f.write(line)
    return HttpResponse('ok')
  return render(request,'upload.html')

总结

完成上述基本文件上传示例后,需注意以下关键点: 1. form表单中必须包含csrf_token验证标签。 2. 文件输入框的type属性值必须设置为file。 3. 在视图函数中获取上传文件时,需使用request.FILES.get()方法。 4. 可通过obj.name属性获取上传文件的原始文件名。

2 将文件上传到数据库

models.py

from django.db import models
 class User(models.Model):
  username = models.CharField(max_length=16)
  avatar = models.FileField(upload_to='avatar')

views.py

def upload(request):
  if request.method == 'POST':
    name = request.POST.get('username')
    avatar = request.FILES.get('avatar')
    models.User.objects.create(username=name,avatar=avatar)
    return HttpResponse('ok') 
  return render(request,'upload.html')

总结

实现文件上传至数据库的功能时,需注意以下几点: 1. 所谓“上传到数据库”,并非将图片二进制数据直接存入数据库,而是将文件保存至服务器本地,数据库中仅存储文件路径。用户调用文件时,通过该路径在服务器指定位置查找。 2. 创建ORM模型时,avatar字段需设置upload_to=''属性,以指定文件上传后的存储目录。 3. 向数据库添加记录时,文件字段的赋值方式与普通字段形式一致,例如:models.User.objects.create(username=name,avatar=avatar)。 4. 若不同用户上传的文件名重复,系统会自动重命名文件,效果如下:

附加

功能实现后,看似只需通过数据库中的文件路径及文件本身即可访问图片并显示在网页上,但实际上并非如此。

我们需要进行额外配置,Django才能识别并找到这些文件,否则URL验证将无法通过。之所以可以直接访问static目录下的静态文件,是因为Django已默认配置好相关路径。

配置步骤如下:

1、在站点的setting.py里配置

MEDIA_ROOT=os.path.join(BASE_DIR,"blog","media") #blog是项目名,media是约定成俗的文件夹名

MEDIA_URL="/media/"   # 跟STATIC_URL类似,指定用户可以通过这个路径找到文件

2、在urls.py里配置

from django.views.static import serve
from upload import settings        #upload是站点名
url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),

配置完成后,即可通过http://127.0.0.1:8001/media/milk.png访问到图片。

3 用AJAX提交文件

upload.html

<!DOCTYPE html>

<html lang="en">
<head>
  <meta charset="UTF-8">
</head>
<body>
<form>
  {% csrf_token %}
  <div>用户名:<input id="name-input" type="text"></div>

  <div>头像<input id="avatar-input" type="file"></div>
  <input id="submit-btn" type="button" value="提交">
</form>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
  $('#submit-btn').on('click',function () {
    formdata = new FormData();
    formdata.append('username',$('#name-input').val());
    formdata.append("avatar",$("#avatar")[0].files[0]);
    formdata.append("csrfmiddlewaretoken",$("[name='csrfmiddlewaretoken']").val()); 
 $.ajax({
 processData:false,contentType:false,url:'/upload', type:'post', data:formdata,success:function (arg)
 { 
if (arg.state == 1){ alert('成功!') }
else { alert('失败!') } } }) });
 </script>
 </body> 
</html>

views.py

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from app01 import models
def upload(request):
  if request.method == 'POST':
    name = request.POST.get('username')
    avatar = request.FILES.get('avatar')
    try:
      models.User.objects.create(username=name,avatar=avatar)
      data = {'state':1}
    except:
      data = {'state':0}
    return JsonResponse(data)
  return render(request,'upload.html')

总结

1. 使用Ajax上传时,按钮的type属性切勿设置为submit。 2. 使用Ajax上传时,data参数的值不再是普通的字典类型,而应为FormData对象。

  1. 创建对象formdata = new FormData();
  2. 向其中添加值formdata.append('username',$('#name-input').val());

3. Ajax进行POST提交时,必须包含csrf验证。

  1. formdata.append("csrfmiddlewaretoken",$("[name='csrfmiddlewaretoken']").val());

4. 最后,Ajax上传文件时需设置两个关键参数。

  1. processData:false
  2. contentType:false

4 上传图片文件的时候有预览功能

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
</head>
<body>
<form>
  <!----用一个label标签将上传文件输入框跟图片绑定一起,
     点击图片的时候就相当于点击了上传文件的按钮---->
  <label><img id="avatar-img" src="/static/img/default.png" width="80px" height="80px">
    <div>头像<input id="avatar-input" hidden type="file"></div>

  </label>
  <input id="submit-btn" type="button" value="提交">
</form>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
  // 上传文件按钮(label里的图片)点击事件
  $('#avatar-input').on('change',function () {
    // 获取用户最后一次选择的图片
    var choose_file=$(this)[0].files[0];
    // 创建一个新的FileReader对象,用来读取文件信息
    var reader=new FileReader();
    // 读取用户上传的图片的路径
    reader.readAsDataURL(choose_file);
    // 读取完毕之后,将图片的src属性修改成用户上传的图片的本地路径
    reader.onload=function () {
       $("#avatar-img").attr("src",reader.result)
    }
  });
</script>

5 大总结

对于文件上传,无论是直接Form提交还是Ajax提交,核心问题在于告知浏览器上传的是文件而非普通字符串。

如何告知浏览器?通过请求体中的ContentType参数。上传普通字符串时无需指定,因其有默认值;

若需传输文件,则必须另行指定。总结如下: 1. Form表单上传通过 enctype="multipart/form-data" 指定ContentType。 2. Ajax上传通过 processData:false 和 contentType:false 指定ContentType。 3. Form上传时,文件数据由<input type="file">标签“包裹”。 4. Ajax上传时,通过FormData实例对象添加数据,传递该对象即可。 5. 数据传递至服务器后,封装在request.FILES中,而非request.POST中。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。