文件上传
关于文件上传
修改myproject/myproject/urls.py
添加路由
# 上传文件
path('upload/list/', upload.upload_list),
新建myproject/app01/views/upload.py
from django.shortcuts import render, HttpResponse
def upload_list(request):
if request.method == "GET":
return render(request, 'upload_list.html')
print(request.POST) #请求中的数据
print(request.FILES) #请求发过来的文件
return HttpResponse("...")
新建myproject/app01/templates/upload_list.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="username">
<input type="file" name="avatar">
<input type="submit" value="提交">
</form>
</div>
{% endblock %}
注意:
不添加 enctype="multipart/form-data"得到的是<QueryDict: {'csrfmiddlewaretoken': ['OeDA7cKmsOLEneNjULy6Isg0hn6GazDOYkLHPrfHrHOLMuLzNNMRuhENQASgz8o9'], 'username': ['123'], 'avatar': ['20200119123801_bjxpj.jpg']}>文件那返回的是文件名的字符串,并不是文件
添加 enctype="multipart/form-data"得到的是<QueryDict: {'csrfmiddlewaretoken': ['TNDydKrOMZ6Vcn6jdhrEhs34WSR1fMEZ3TLFVZW9LS92BD4z6jFp3hrRv5DBElpk'], 'username': ['222']}><MultiValueDict: {'avatar': [<InMemoryUploadedFile: 20200119123801_bjxpj.jpg (image/jpeg)>]}>
添加后才能得到文件
修改myproject/app01/views/upload.py
from django.shortcuts import render, HttpResponse
def upload_list(request):
if request.method == "GET":
return render(request, 'upload_list.html')
# print(request.POST) #请求中的数据
# print(request.FILES) #请求发过来的文件
# 声明图片的对象
file_object = request.FILES.get("avatar")
# 分块进行存储
# file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字
f = open(file_object.name, mode='wb')
for chunk in file_object.chunks():
f.write(chunk)
f.close()
return HttpResponse("上传成功")



案例:批量上传数据
实现:表格上传至服务器并将数据读取保存至数据库中
我们在部门管理代码的基础上进行操作
修改myproject/app01/templates/depart.html
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
批量上传
</div>
<div class="panel-body">
<form method="post" enctype="multipart/form-data" action="/depart/multi/">
{% csrf_token %}
<div class="form-group">
<input type="file" name="exc">
</div>
<input type="submit" value="上传" class="btn btn-info btn-sm">
</form>
</div>
</div>

安装openpyxl
pip install openpyxl
修改myproject/app01/views/depart.py
def depart_multi(request):
"""批量上传Excel文件"""
from openpyxl import load_workbook
#1.获取用户上传的文件对象
file_object = request.FILES.get("exc")
print(type(file_object))
#2.把对象传递给openpyxl,由openpyxl读取文件的内容
wb = load_workbook(file_object)
sheet = wb.worksheets[0]
#cell = sheet.cell(1,1) 获取第一行的第一个数据
#3.循环获取每一行数据
for row in sheet.iter_rows(min_row=2):
text = row[0].value
print(text)
#部门重复的不添加
exists = models.Department.objects.filter(title=text).exists()
if not exists:
#4.添加到数据库
models.Department.objects.create(title=text)
return redirect('/depart/list/')

编辑myproject/myproject/urls.py
path('depart/multi/', depart.depart_multi),
浏览器访问测试
手动创建一个表格,填入如下内容
将表格进行上传
这里会存在一个问题,如果上传的字段就为空,页面就会报错处理起来也简单,针对为空的情况做一下简单的判断即可
案例:混合数据上传(Form)
提交页面时:用户输入的数据+文件(输入不能为空、报错都要有)
编辑myprojrct/app01/templates/layout.html
<li><a href="/upload/form/">Form上传</a></li>
添加路由
编辑myproject/myproject/urls.py
path('upload/form/', upload.upload_form),编写视图函数
编辑myprojrct/app01/views.py/upload.py
from django.shortcuts import render, HttpResponse def upload_list(request): if request.method == "GET": return render(request, 'upload_list.html') # print(request.POST) #请求中的数据 # print(request.FILES) #请求发过来的文件 # 声明图片的对象 file_object = request.FILES.get("avatar") # 分块进行存储 # file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字 f = open(file_object.name, mode='wb') for chunk in file_object.chunks(): f.write(chunk) f.close() return HttpResponse("上传成功") from django import forms from app01.utils.bootstrap import BootStrapForm class UpForm(BootStrapForm): name = forms.CharField(label="姓名") age = forms.IntegerField(label="年龄") img = forms.FileField(label="头像") def upload_form(request): title = "Form上传" form = UpForm() return render(request, 'upload_form.html', {"form":form, "title":title})
新建upload_form.html
编辑myproject/app01/templates/upload_form.html
{% extends 'layout.html' %} {% block content %} <div class="container"> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">{{ title }}</h3> </div> <div class="panel-body"> {# novalidate去除浏览器的错误提示 #} <form method="post" enctype="multipart/form-data" novalidate> {% csrf_token %} {% for field in form %} <div class="form-group"> <label>{{ field.label }}</label> {{ field }} {# {{ field.errors }}错误信息是一个列表[错误1,错误2,错误3...], {{ field.errors.0 }}只取第一个错误1 #} <span style="color: red;">{{ field.errors.0 }}</span> {# <input type="text" class="form-control" placeholder="姓名" name="user"> #} </div> {% endfor %} <button type="submit" class="btn btn-primary">提 交</button> </form> </div> </div> </div> {% endblock %}浏览器访问,会发现有一个问题,上传图片的输入框也添加了bootstrap样式:
去除上传图片输入框的bootstrap样式:
修改myproject/app01/utils/bootstrap.py
from django import forms class BootStrap: #如果哪个输入框不想用BootStrap样式 bootstrap_exclude_fields = [] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 循环找到所有的插件,添加class = "form-control"样式 for name, field in self.fields.items(): # 如果哪个输入框不想用BootStrap样式,把name写出来 if name in self.bootstrap_exclude_fields: continue #字段中有属性,保留原来的属性,没有属性,才增加 if field.widget.attrs: field.widget.attrs["class"] = "form-control" field.widget.attrs["placeholder"] = field.label else: field.widget.attrs = { "class": "form-control", "placeholder": field.label } class BootStrapModelForm(BootStrap, forms.ModelForm): pass class BootStrapForm(BootStrap, forms.Form): pass
修改myproject/app01/vierws/upload.py
bootstrap_exclude_fields = ['img']
接下来实现图片的上传(保存至本地与数据库)
新创建一个表
编辑myproject/app01/models.py
class Boss(models.Model): """老板""" name = models.CharField(verbose_name="姓名", max_length=32) age = models.IntegerField(verbose_name="年龄") img = models.CharField(verbose_name="头像", max_length=128)执行
makemigrations migrate修改myproject/app01/views/upload.py
import os from django.shortcuts import render, HttpResponse from app01 import models def upload_list(request): if request.method == "GET": return render(request, 'upload_list.html') # print(request.POST) #请求中的数据 # print(request.FILES) #请求发过来的文件 # 声明图片的对象 file_object = request.FILES.get("avatar") # 分块进行存储 # file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字 f = open(file_object.name, mode='wb') for chunk in file_object.chunks(): f.write(chunk) f.close() return HttpResponse("上传成功") from django import forms from app01.utils.bootstrap import BootStrapForm class UpForm(BootStrapForm): bootstrap_exclude_fields = ['img'] name = forms.CharField(label="姓名") age = forms.IntegerField(label="年龄") img = forms.FileField(label="头像") def upload_form(request): title = "Form上传" if request.method == "GET": form = UpForm() return render(request, 'upload_form.html', {"form":form, "title":title}) form = UpForm(data=request.POST, files=request.FILES) if form.is_valid(): #cleaned_data:{'name': '方法', 'age': 11, 'img': <InMemoryUploadedFile: 20200119123801_bjxpj.jpg (image/jpeg)>} #print(form.cleaned_data) #读取到内容,自己处理每个字段的数据 #1.读取图片内容,写入文件夹中并获取文件的路径 image_object = form.cleaned_data.get("img") #file_path = "app01/static/img/{}".format(image_object.name) #win系统和Linux系统/有差别,建议用os做拼接 file_path = os.path.join("app01","static", "img", image_object.name) f = open(file_path, mode='wb') for chunk in image_object.chunks(): f.write(chunk) f.close() #2.将图片文件路径写入到数据库 models.Boss.objects.create( name=form.cleaned_data['name'], age=form.cleaned_data['age'], img=file_path, ) return HttpResponse("...") return render(request, 'upload_form.html', {"form":form, "title":title})
数据库中查看新增数据
此时查看图片地址:http://127.0.0.1:8000/app01/static/img+图片文件名
怎么把app01去掉,直接http://127.0.0.1:8000/static/img+图片文件名 访问呢
修改myproject/app01/views/upload.py
def upload_form(request): title = "Form上传" if request.method == "GET": form = UpForm() return render(request, 'upload_form.html', {"form":form, "title":title}) form = UpForm(data=request.POST, files=request.FILES) if form.is_valid(): #cleaned_data:{'name': '方法', 'age': 11, 'img': <InMemoryUploadedFile: 20200119123801_bjxpj.jpg (image/jpeg)>} #print(form.cleaned_data) #读取到内容,自己处理每个字段的数据 #1.读取图片内容,写入文件夹中并获取文件的路径 image_object = form.cleaned_data.get("img") #file_path = "app01/static/img/{}".format(image_object.name) #win系统和Linux系统/有差别,建议用os做拼接 db_file_path = os.path.join("static", "img", image_object.name) file_path = os.path.join("app01",db_file_path) f = open(file_path, mode='wb') for chunk in image_object.chunks(): f.write(chunk) f.close() #2.将图片文件路径写入到数据库 models.Boss.objects.create( name=form.cleaned_data['name'], age=form.cleaned_data['age'], img=db_file_path, ) return HttpResponse("...") return render(request, 'upload_form.html', {"form":form, "title":title})
浏览器新增加一条数据
就目前而言,所有的静态文件都只能放在static目录
后续可以分开
static存放项目的静态文件
media目录存放用户上传的文件
在django开发过程中有两个特殊的文件夹
static:存放静态文件的路径,包括CSS、JS、项目图片
media:用户上传的数据的目录,但是使用 media 需要做一些配置
启用media
1.在urls.py中进行配置
from django.urls import path, re_path from django.views.static import serve from django.conf import settings urlpatterns = [ # path('admin/', admin.site.urls), re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
]
2.在settings中进行配置
import os
MEDIA_ROOT = os.path.join(BASE_DIR, "media") MEDIA_URL = "/media/"
新建目录
myproject/media配置后就可以在浏览器上访问地址了:127.0.0.1;8000/media/+图片名字
我们来修改一下上面图片的上传路径试试吧
修改myproject/app01/views/upload.py
import os from django.conf import settings from django.shortcuts import render, HttpResponse from app01 import models def upload_list(request): if request.method == "GET": return render(request, 'upload_list.html') # print(request.POST) #请求中的数据 # print(request.FILES) #请求发过来的文件 # 声明图片的对象 file_object = request.FILES.get("avatar") # 分块进行存储 # file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字 f = open(file_object.name, mode='wb') for chunk in file_object.chunks(): f.write(chunk) f.close() return HttpResponse("上传成功") from django import forms from app01.utils.bootstrap import BootStrapForm class UpForm(BootStrapForm): bootstrap_exclude_fields = ['img'] name = forms.CharField(label="姓名") age = forms.IntegerField(label="年龄") img = forms.FileField(label="头像") def upload_form(request): title = "Form上传" if request.method == "GET": form = UpForm() return render(request, 'upload_form.html', {"form":form, "title":title}) form = UpForm(data=request.POST, files=request.FILES) if form.is_valid(): #cleaned_data:{'name': '方法', 'age': 11, 'img': <InMemoryUploadedFile: 20200119123801_bjxpj.jpg (image/jpeg)>} #print(form.cleaned_data) #读取到内容,自己处理每个字段的数据 #1.读取图片内容,写入文件夹中并获取文件的路径 image_object = form.cleaned_data.get("img") #file_path = "app01/static/img/{}".format(image_object.name) #win系统和Linux系统/有差别,建议用os做拼接 #db_file_path = os.path.join("static", "img", image_object.name) media_path = os.path.join(settings.MEDIA_ROOT, image_object.name) f = open(media_path, mode='wb') for chunk in image_object.chunks(): f.write(chunk) f.close() #2.将图片文件路径写入到数据库 models.Boss.objects.create( name=form.cleaned_data['name'], age=form.cleaned_data['age'], img=media_path, ) return HttpResponse("...") return render(request, 'upload_form.html', {"form":form, "title":title})
返回的是绝对路径 C:\Users\lenovo\Desktop\dj_base\pythoncode\gx\day16\media\84268f771c2c053555fb28a860134baf.jpeg若不想用绝对路径,改为相对路径
修改myproject/app01/views/upload.py
#settings.MEDIA_ROOT返回的是绝对路径 C:\Users\lenovo\Desktop\dj_base\pythoncode\gx\day16\media\84268f771c2c053555fb28a860134baf.jpeg #media_path = os.path.join(settings.MEDIA_ROOT, image_object.name) #相对路径 media_path = os.path.join("media", image_object.name)
案例:混合数据上传(ModelForm)
新加一个按钮
编辑myproject/app01/templates/layout.html
<ul class="nav navbar-nav"> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">功能管理 <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="/admin/list/">管理员账户管理</a></li> <li><a href="/depart/list/">部门管理</a></li> <li><a href="/user/list/">用户管理</a></li> <li><a href="/prettynum/list/">靓号管理</a></li> <li><a href="/task/list/">任务管理</a></li> </ul> </li> <li><a href="/chart/list/">数据统计</a></li> <li><a href="/chart/highcharts/">Highcharts</a></li> <li><a href="/upload/list/">上传图片</a></li> <li><a href="/upload/form/">Form上传</a></li> <li><a href="/upload/model/form/">ModelForm上传</a></li> </ul>添加路由
编辑myproject/myproject/urls.py
path('upload/model/form/', upload.upload_model_form),编辑
myproject/myproject/models.py创建一个新的数据库class City(models.Model): """城市""" name = models.CharField(verbose_name="名称", max_length=32) count = models.IntegerField(verbose_name="人口") #本质上数据库中也是CharField,FileField可以自动保存数据 img = models.FileField(verbose_name="LOGO", max_length=128, upload_to='city/')执行命令
makemigrations migrate编写视图函数myproject/app01/views/upload.py
import os from django.conf import settings from django.shortcuts import render, HttpResponse from app01 import models def upload_list(request): if request.method == "GET": return render(request, 'upload_list.html') # print(request.POST) #请求中的数据 # print(request.FILES) #请求发过来的文件 # 声明图片的对象 file_object = request.FILES.get("avatar") # 分块进行存储 # file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字 f = open(file_object.name, mode='wb') for chunk in file_object.chunks(): f.write(chunk) f.close() return HttpResponse("上传成功") from django import forms from app01.utils.bootstrap import BootStrapForm, BootStrapModelForm class UpForm(BootStrapForm): bootstrap_exclude_fields = ['img'] name = forms.CharField(label="姓名") age = forms.IntegerField(label="年龄") img = forms.FileField(label="头像") def upload_form(request): title = "Form上传" if request.method == "GET": form = UpForm() return render(request, 'upload_form.html', {"form":form, "title":title}) form = UpForm(data=request.POST, files=request.FILES) if form.is_valid(): #cleaned_data:{'name': '方法', 'age': 11, 'img': <InMemoryUploadedFile: 20200119123801_bjxpj.jpg (image/jpeg)>} #print(form.cleaned_data) #读取到内容,自己处理每个字段的数据 #1.读取图片内容,写入文件夹中并获取文件的路径 image_object = form.cleaned_data.get("img") #file_path = "app01/static/img/{}".format(image_object.name) #win系统和Linux系统/有差别,建议用os做拼接 #db_file_path = os.path.join("static", "img", image_object.name) #settings.MEDIA_ROOT返回的是绝对路径 C:\Users\lenovo\Desktop\dj_base\pythoncode\gx\day16\media\84268f771c2c053555fb28a860134baf.jpeg #media_path = os.path.join(settings.MEDIA_ROOT, image_object.name) #相对路径 media_path = os.path.join("media", image_object.name) f = open(media_path, mode='wb') for chunk in image_object.chunks(): f.write(chunk) f.close() #2.将图片文件路径写入到数据库 models.Boss.objects.create( name=form.cleaned_data['name'], age=form.cleaned_data['age'], img=media_path, ) return HttpResponse("...") return render(request, 'upload_form.html', {"form":form, "title":title}) class UpModelForm(BootStrapModelForm): bootstrap_exclude_fields = ['img'] class Meta: model = models.City fields = "__all__" def upload_model_form(request): """上传文件和数据(modelform)""" title = "ModelForm上传文件" if request.method == "GET": form = UpModelForm() return render(request, 'upload_form.html', {"form": form, "title": title}) form = UpModelForm(data=request.POST, files=request.FILES) if form.is_valid(): #对于文件自动保存 #字段+上传路径写入到数据库 form.save() return HttpResponse("成功") return render(request, 'upload_form.html', {"form": form, "title": title})
小结
1.自己动手写
file_object = request.FILES.get("exc") ...2.Form组件(表单验证)
request.POST file_object = request.FILES.get("exc") 具体文件操作还是需要手动做3.ModelForm(表单验证 + 自动保存数据库 + 自动保存文件)
-配置Media文件夹 -Models.py定义文件要填写路径upload_to='路径' img = models.FileField(verbose_name="LOGO", max_length128, upload_to = 'city/')



这里会存在一个问题,如果上传的字段就为空,页面就会报错处理起来也简单,针对为空的情况做一下简单的判断即可

























浙公网安备 33010602011771号