ModelForm结合Bootstrap实现拖拽文件上传
前言
在由于Bootstrap3没有对文件上传的input框提供样式支持,导致在我们使用Bootstrap3增加表单样式时,文件框就会显得很单一,或者需要自己重新写,降低了开发效率,这里讲解一下怎么解决问题,附加实现拖拽文件上传
正文
1、演示场景
models.py
class FileTest(models.Model):""" 文件上传测试 """title = models.CharField(verbose_name="名称",max_length=128)file = models.FileField(verbose_name="文件",max_length=128,upload_to='test/')
forms.py
class FileTestModel(forms.ModelForm):def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)for name, field in self.fields.items():if field.widget.attrs:field.widget.attrs['class'] = 'form-control'field.widget.attrs['placeholder'] = '请输入' + field.labelelse:field.widget.attrs = {'class': 'form-control', 'placeholder': '请输入' + field.label}class Meta:model = models.FileTestfields = "__all__"
2、视图处理
views.py
from django.shortcuts import render,HttpResponse
from app01.utils.form import FileTestModel
def upload_test(request):if request.method == "GET":test = FileTestModel()return render(request,'upload_test.html',{"test": test})test = FileTestModel(request.POST,request.FILES)if test.is_valid():test.save()return HttpResponse("成功")return render(request,'upload_test.html',{"test": test})
3、补充
bootstrap3没有提供对于表单文件框的演示处理
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title><link rel="stylesheet" href="static/plugins/bootstrap-3.4.1/css/bootstrap.css"></head><body><div class="col-md-4" style="margin-top: 20px;"><input class="form-control" type="file" /></div></body>
</html>
效果:

很丑,而且不是我们想要的效果
Bootstrap5处理了这个问题
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title><link rel="stylesheet" href="static/plugins/bootstrap-5.2.3/css/bootstrap.css" /></head><body><div class="col-md-4" style="margin-top: 20px;"><input class="form-control" type="file" /></div></body>
</html>
效果:

4、前端处理
利用jQuery和Bootstrap5实现拖拽上传
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>文件上传</title><link rel="stylesheet" href="{% static 'plugins/bootstrap-5.2.3/css/bootstrap.css' %}"><script src="{% static 'plugins/jQuery/jquery-3.7.1.js' %}"></script>
</head>
<body>
<div class="container"><form method="post" enctype="multipart/form-data" id="uploadForm">{% csrf_token %}<div class="col-md-6" style="margin-top: 20px"><label>{{ test.title.label }}</label>{{ test.title }}</div><!-- 文件上传区域 --><div class="col-md-6" style="margin-top: 20px"><label>文件</label><div class="border rounded p-4 text-center" id="dropZone" style="cursor: pointer;"><div id="dropZoneContent"><p class="text-muted mb-2">点击或拖拽文件到此处上传</p><span class="badge bg-secondary">选择文件</span></div><div id="fileName" class="mt-2 fw-bold" style="display: none;"></div></div><!-- 隐藏的文件输入 --><input type="file" class="d-none" name="file" id="fileInput"></div><button type="submit" class="btn btn-primary" style="margin-top: 20px">提交表单</button></form>
</div><script>$(document).ready(function() {const dropZone = $('#dropZone');const fileInput = $('#fileInput');const fileName = $('#fileName');dropZone.on('click', function() {fileInput.click();});$(document).on('dragover dragenter', function(e) {e.preventDefault();e.stopPropagation();});$(document).on('drop', function(e) {e.preventDefault();e.stopPropagation();});dropZone.on('dragover dragenter', function(e) {e.preventDefault();e.stopPropagation();$(this).addClass('border-primary bg-light');});dropZone.on('dragleave', function(e) {e.preventDefault();e.stopPropagation();const x = e.pageX;const y = e.pageY;const offset = $(this).offset();if (x < offset.left || x >= offset.left + $(this).width() ||y < offset.top || y >= offset.top + $(this).height()) {$(this).removeClass('border-primary bg-light');}});dropZone.on('drop', function(e) {e.preventDefault();e.stopPropagation();$(this).removeClass('border-primary bg-light');const files = e.originalEvent.dataTransfer.files;if (files.length > 0) {fileInput[0].files = files;updateFileName(files[0].name);}});fileInput.on('change', function() {if (this.files.length > 0) {updateFileName(this.files[0].name);}});function updateFileName(name) {fileName.text(name).show();$('#dropZoneContent .badge').removeClass('bg-secondary').addClass('bg-success').text('文件已选择');}});
</script>
</body>
</html>
5、隔离出来的文件上传区域(复制直接看这里)
导入Bootstrap5和jQuery后可直接粘贴使用
html部分
<div class="col-md-6" style="margin-top: 20px"><label>文件</label><div class="border rounded p-4 text-center" id="dropZone" style="cursor: pointer;"><div id="dropZoneContent"><p class="text-muted mb-2">点击或拖拽文件到此处上传</p><span class="badge bg-secondary">选择文件</span></div><div id="fileName" class="mt-2 fw-bold" style="display: none;"></div></div><input type="file" class="d-none" name="file" id="fileInput">
</div>
js部分
$(document).ready(function() {const dropZone = $('#dropZone');const fileInput = $('#fileInput');const fileName = $('#fileName');dropZone.on('click', function() {fileInput.click();});$(document).on('dragover dragenter', function(e) {e.preventDefault();e.stopPropagation();});$(document).on('drop', function(e) {e.preventDefault();e.stopPropagation();});dropZone.on('dragover dragenter', function(e) {e.preventDefault();e.stopPropagation();$(this).addClass('border-primary bg-light');});dropZone.on('dragleave', function(e) {e.preventDefault();e.stopPropagation();const x = e.pageX;const y = e.pageY;const offset = $(this).offset();if (x < offset.left || x >= offset.left + $(this).width() ||y < offset.top || y >= offset.top + $(this).height()) {$(this).removeClass('border-primary bg-light');}});dropZone.on('drop', function(e) {e.preventDefault();e.stopPropagation();$(this).removeClass('border-primary bg-light');const files = e.originalEvent.dataTransfer.files;if (files.length > 0) {fileInput[0].files = files;updateFileName(files[0].name);}});fileInput.on('change', function() {if (this.files.length > 0) {updateFileName(this.files[0].name);}});function updateFileName(name) {fileName.text(name).show();$('#dropZoneContent .badge').removeClass('bg-secondary').addClass('bg-success').text('文件已选择');}
});
这里的model中文件的字段名叫file
如果你的不叫file
在html部分将
<input type="file" class="d-none" name="file" id="fileInput">
中的name改为对应的名字即可
效果:


