背景:利用 Form 收集用户提交的信息,包括字符串和文件对象,文件保存在项目的 media 文件夹,因为 static 文件一般是用来存静态文件 css 或者项目所需要的图片,用户上传的文件应该保存在其他文件夹;
1、 启用 media,在项目根目录创建 media 文件夹(与manage.py文件同级)
urls.py 需要新增如下
...
from django.urls import re_path
from django.views.static import serve
from django.conf import settings
urlpatterns = [
re_path(r'^media/(?P<path>.*)$',serve,{'document_root':settings.MEDIA_ROOT},name='media'),
...
]
settings.py 需要新增如下
MEDIA_ROOT = os.path.join(BASE_DIR,"media")
MEDIA_URL = "/media/"
2、设置好之后在 media 文件夹下放一个图片就能够直接访问了
3、 案例:
用户上传自己的姓名、年龄、头像
上传成功之后:查看数据库
4、案例实现
4.1、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)
4.2、创建 url 链接
from .views import upload_form
urlpatterns = [
path('upload/form',upload_form),# form 上传
]
4.3、创建视图函数 views.py
def upload_form(request):
title = "Form上传"
if request.method == 'GET':
form = UpForm()
return render(request,'upload_form.html',{"form":form,"title":title})
if request.method == 'POST':
form = UpForm(data=request.POST,files=request.FILES)
if form.is_valid():
print(form.cleaned_data)
# {'name': '测试', 'age': 23, 'img': <InMemoryUploadedFile: 电信科技.png (image/png)>}
# 1、读取图片内容,写入到文件夹中并获取文件的路径
image_object = form.cleaned_data.get("img")
# file_path = "appback/static/img/{}".format(image_object.name) # 这种写法不同操作系统会出问题
# file_path = os.path.join("appback","static","img",image_object.name) # 将文件写入appback/tatic/img
from django.conf import settings
# db_file_path = os.path.join(settings.MEDIA_ROOT,image_object.name) # 将文件写入 media 文件夹 settings.MEDIA_ROOT # 绝对路径
db_file_path = os.path.join("media", image_object.name)
f = open(db_file_path,mode="wb")
for chunk in image_object.chunks():
f.write(chunk)
f.close()
# 2、将图片文件路径写入到数据库中
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})
tips1:文件路径建议使用 os.path.join 拼接而不要使用下面这种方式,因为linux 与 windows 不同操作系统可能会出现问题。
file_path = "appback/static/img/{}".format(image_object.name)
tips2:存入数据库的是文件的路径,可以是绝对路径也可以是相对路劲。
绝对路径:
db_file_path = os.path.join(settings.MEDIA_ROOT,image_object.name)
相对路径:
db_file_path = os.path.join("media", image_object.name)
tips3: 文件是分块上传的到内存的,因此保存的时候利用循环读取保存到本地
例如上传一个excel 文件,上传成功以后打印它的文件对象类型
<class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
file_object = request.FILES.get('excel')
print(type(file_object)) # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
查看这个对象的方法,按住ctrl 点击 InMemoryUploadedFile
from django.core.files.uploadedfile import InMemoryUploadedFile
可以看到这个对象中的方法,这里我们需要把这个文件对象读出来,保存到本地,因此使用对象的 chunks 方法。
f = open(db_file_path,mode="wb")
for chunk in image_object.chunks():
f.write(chunk)
f.close()
tips4:如果是 excel 可以直接使用第三方 openpyxl 库直接读取文件对象,因为它load_workbook支持传入一个文件对象。
from openpyxl import load_workbook
wb = load_workbook(file_object)
4.4 模板文件html
<!--该html 继承模板 layout.html-->
{% extends 'layout.html' %}
{% block content %}
<div>
<h3>{{title}}</h3>
<form method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{% for field in form %}
{{ field.label }}:{{field}}
<span style="color:red;">{{field.errors.0}}</span>
{% endfor %}
<input type="submit" value="提交">
</form>
</div>
{% endblock %}
以上就是利用 Form 收集用户提交的数据包括上传的文件保存到本地,写入数据库中的全部内容了。下期更新更简单的 ModelForm 上传。