django 原生文件上传
#html页面
<form action="/upload/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>姓名:<input type="text" name="sname"></p>
<p>图片:<input type="file" name="photo"></p>
<p><input type="submit" value="提交"></p>
</form>
# 注意注意啦:文件上传必须写method="post" enctype="multipart/form-data
#views.py文件代码:
from django.http import HttpResponse
from django.shortcuts import render
import os
from demo6.settings import BASE_DIR
def upload_index(request):
if request.method == "GET":
return render(request,"upload.html")
elif request.method == "POST":
# 获取请求参数
sname = request.POST.get("sname")
photo = request.FILES.get("photo")
# print(type(photo))的输出结果为上传文件对象,如下
# <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
# print(photo)的输出结果如下
# 1567516976(1).jpg
# 判断文件目录是否存在
# settings.py文件中
# BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 指的是当前文件 的绝对路径 的目录 的目录
m_path = os.path.join(BASE_DIR, "images") # images指的是文件夹名
if not os.path.exists(m_path):
# 如果项目目录下没有images目录,则会新建一个
os.mkdir(m_path)
with open(os.path.join(m_path,photo.name), "wb") as f:
# 一次性将文件读取到内存
# f.write(photo.read())
#分块读取文件到内存
for c in photo.chunks():
f.write(c)
return HttpResponse("上传成功")
- photo.read():从文件中读取整个上传的数据,这个方法只适合小文件;
- photo.chunks():按块返回文件,通过在for循环中进行迭代,可以将大文件按块写入到服务器中;
- photo.multiple_chunks():这个方法根据myFile的大小,返回True或者False,当myFile文件大于2.5M(默认为2.5M,可以调整)时,该方法返回True,否则返回False,因此可以根据该方法来选择选用read方法读取还是采用chunks方法
- photo.name:这是一个属性,不是方法,该属性得到上传的文件名,包括后缀,如123.exe;
- photo.size:这也是一个属性,该属性得到上传文件的大小。
Django文件上传到数据库 并调用显示在页面中
并实现文件的预览与下载
环境:Python 3.6.0 Django 2.2.4
需求
- 完成学生信息注册操作 访问路径 GET /student/upload/ POST /student/upload/
- 将表单数据保存到数据库 访问路径 GET /student/upload/ POST /student/upload/
- 将上传文件存放至项目下media文件夹下
- 将用户提交的数据显示在页面中 访问路径 GET /student/showall/
创建模型类
from django.db import models
class Student(models.Model):
sname = models.CharField(max_length=30)
age = models.PositiveIntegerField()
photo = models.ImageField(upload_to='imgs/')
# 上面要写相对路径前面不能加/
# 上传文件(ImageField,FileField)
# 如果创建的表中有ImageField数据类型,要先pip install Pillow
# 图片保存到项目下的某个文件夹下
# upload_to='imgs/'默认保存到项目根目录下的imgs文件夹下面
# 本质文件上传后存储的位置=setting.py文件MEDIA_ROOT + UPLOAD_to
settings.py文件中文件上传相关设置
# 引包
# global_settings
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# BASE_DIR指的是项目根目录
# 我们需要告诉Django,媒体文件的位置在哪里。
# 这样就和数据库存储的路径相对应了,具体就是MEDIA_ROOT指定目录,upload_to就是在这个目录下进行操作。
映射数据库表
#在终端中敲命令
python manage.py makemigrations stu
python manage.py migrate
配置URL
- test13/urls.py
from django.contrib import admin
from django.urls import path, include, re_path
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path("student/", include("stuapp3.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# serve是Djando提供的视图函数,读取上传文件
# if DEBUG:
# urlpatterns += re_path('media/(?P<path>.*)/', serve, {"document_root": MEDIA_ROOT}),
# 上面的这种配置只适用于Django 1.X版本
# path:imgs/1.jpg
# document_root:media文件夹的绝对路径
# url = d/phthonproject/.../media/imgs/1.jpg
- stu/urls.py
from django.urls import path
from stuapp3 import views
urlpatterns = [
path("upload/", views.upload1_view),
path("showall/", views.showall_view)
]
创建视图
- stu/views.py
from django.http import HttpResponse, Http404
from django.shortcuts import render
from stuapp3.models import Student
def upload1_view(request):
# 表单提交的请求方式只支持get或者post
# 针对其他的请求方式需要使用AJAX
if request.method == "GET":
return render(request, "upload.html")
else:
# 获取请求参数
sname = request.POST.get("sname", "")
age = request.POST.get("age", "")
photo = request.FILES.get("photo", "")
# 校验上传图片的格式(png/jpg)
# 获取文件扩展名
extendname = photo.name[photo.name.rindex(".") + 1:]
# 判断上传文件是否符合格式要求
allowedes = ["png", "jpg"]
if extendname not in allowedes:
return Http404()
# 将数据保存到数据库
stuObj = Student.objects.create(sname=sname,age=age,photo=photo)
# 判断是否注册成功
if stuObj:
return HttpResponse("注册成功")
return HttpResponse("注册失败")
def showall_view(request):
# 查询所有学生信息
stus = Student.objects.all()
return render(request, 'showall.html', {'stus': stus})
创建模板
- templates/upload.html
<body>
<form action="/student/upload/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>姓名:<input type="text" name="sname"></p>
<p>年龄:<input type="text" name="age"></p>
<p>头像:<input type="file" name="photo"></p>
<p> <input type="submit" value="提交"></p>
</form>
</body>
- templates/showall.html
<body>
<table border="1" width="500px" cellspacing="0">
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>头像</th>
<th>操作</th>
</tr>
{% for stu in stus %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ stu.sname }}</td>
<td>{{ stu.age }}</td>
<td><img style="width: 100px" src="{{ MEDIA_URL }}{{ stu.photo }}"/></td>
<td>操作</td>
</tr>
{% endfor %}
</table>
</body>
这里{{ MEDIA_URL }}是必须要的,因为数据库取出来的地址是/logo/img001.png这种,路径不完整,我们存储的路径上/media/logo/img001.png
但到这里还是不能正常显示图片,会显示404,是因为图片的url也是需要通过django进行指派,我们还需要在urls.py进行设定。
为了html模板能正确找到MEDIA_URL,TEMPLATES中导入相关的包。如下所示
头像读取相关settings.py文件中的设置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.media'#配置这句话
],
},
},
]
文件下载 访问路径GET /student/download/
配置子路由URL
from django.urls import path, re_path
from stuapp3 import views
urlpatterns = [
path("upload/", views.upload1_view),
path("showall/", views.showall_view),
re_path("download/(.*)$", views.download_view)
]
创建视图
def download_view(request, photoname):
# 接受请求参数
flag = request.GET.get("flag", "")
# 获取上传的文件名 imgs/1.jpg
filename = photoname[photoname.rindex("/")+1:]
# 获取文件所在的存储位置
url = os.path.join(MEDIA_ROOT, photoname)
# 预览模式
with open(url, "rb") as f:
content = f.read()
response = HttpResponse(content, content_type="image/jpeg")
if flag == "2":
# 附件下载模式
response["Content-Disposition"] = "attachment;filename="+filename
return response
文件名中文情况
from django.utils.encoding import escape_uri_path
response['Content-Disposition'] = "attachment; filename*=utf-8''{}".format(escape_uri_path(file_name))
<body>
<table border="1" width="500px" cellspacing="0">
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>头像</th>
<th>操作</th>
</tr>
{% for stu in stus %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ stu.sname }}</td>
<td>{{ stu.age }}</td>
<td><img style="width: 100px" src="{{ MEDIA_URL }}{{ stu.photo }}"/></td>
<td>
<a href="/student/download/{{ stu.photo }}?flag=1">预览查看</a>
<a href="/student/download/{{ stu.photo }}?flag=2">附件下载</a>
</td>
</tr>
{% endfor %}
</table>
</body>