最近在学习使用django和vue3写一个前后端项目,在上传用户图片这边卡了好一会儿,网上找了好多资料,最后还是自己总结了一点经验,分享给大家。
我在前端使用的是Element plus的el-upload组件上传图片,后端用户的头像字段采用的是ImageField类型。 ImageField是Django数据库的一种数据类型,varchar类型,通常用来保存图片的名称,而想要了解el-upload具体有哪些属性可以参考:Upload 上传 | Element Plus。
两者具体怎么用看下面的流程。
一、 前端代码
首先,上传头像需要用到前端的el-upload组件,如以下代码:
<el-upload
:action="http://127.0.0.1:8000/media/upload/uploadAvatar"
:auto-upload="true"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img
v-if="imageUrl"
:src="imageUrl"
/>
<i v-else></i>
</el-upload>
其中,action规定了上传头像对应的url,这是一会儿要和后端对应上的;auto-upload是自动上传;on–success是上传成功后的操作,而before-upload规定了上传前的操作,通常用来判断图片格式、大小是否满足要求。这里在el-upload里面放了一个img标签,用来显示图片,当imageUrl能从后端请求到图片时就显示图片,否则显示一个空的链接。
下面是我在methods中规定的on-success和before-upload对应的行为:
// 上传成功后进行数据处理
handleAvatarSuccess(res) {
// 显示上传是否成功
if (res.code == 0) {
this.$message.success(res.msg);
} else {
this.$message.error(res.msg);
}
// 规定新的imageUrl为 <"http://127.0.0.1:8000/media/user/"+文件名>
this.imageUrl = "http://127.0.0.1:8000/media/user/" + res.file;
// 更新user的photo字段值
this.user.photo = res.file;
},
// 上传前判断图片大小是否满足要求
beforeAvatarUpload(file) {
const isLt10M = file.size / 1024 / 1024 < 200;
if (!isLt10M) {
this.$message.error('上传头像图片大小不能超过 200MB!');
}
return isLt10M;
},
至此,前端部分基本上编写完成。界面如下(这里我没给出css样式,大家自行解决咯):
二、后端代码
后端的django需要接收到前端的请求并作出相应处理。这里要着重区分两个请求:一个是上传图片的请求,也就是el-upload中:action对应的请求;另一个是图片上传后显示图片的请求,也就是img标签中:src对应的值。接下来我们拆分成两点进行分析。
1. 上传图片
在上传图片前,先在models.py文件下写一个user类,可以参考下面的代码:
class User(models.Model):
username = models.CharField(max_length=30, unique=True)
password = models.CharField(max_length=20)
photo = models.ImageField(max_length=100, blank=True, null=True, default='')
# 可以自己添加其他字段
其中photo字段用的是ImageField类型(不过本人实测过,如果存储的仅仅是图片名称的话,用CharField也是完全OK的,没有影响)
# 头像保存路径
USER_AVATAR_ROOT = os.path.join(BASE_DIR, 'static/images/user')
USER_AVATAR_ROOT指定了头像保存的路径,即<根目录 + static/images/user> ,大家可以自行替换。
path("media/upload/uploadAvatar", views.saveImage),
这个路径对应的就是el-upload中的action路径,也就是当用户在前端界面选择了一个头像时,el-upload会自动发送action规定的post请求,给后端处理,我这里规定的是”media/upload/uploadAvatar“,大家可以自行替换,但要保证前后端的请求url一致。
最后就是编写views.py中的saveImage函数,该函数用来保存图片至指定的路径,也就是实现图片上传功能:
def saveImage(request):
response = {}
# 获取前端发来的的file对象
file = request.FILES.get('file')
try:
# 构造图片保存路径 路径为<USER_AVATAR_ROOT + 文件名>
# USER_AVATAR_ROOT刚刚在settings.py中规定过,需要导入进来
file_path = os.path.join(USER_AVATAR_ROOT, file.name)
# 保存图片
with open(file_path, 'wb+') as f:
f.write(file.read())
f.close()
response['file'] = file.name # 返回新的文件名
response['code'] = 0
response['msg'] = "图片上传成功!"
except:
response['file'] = ''
response['code'] = 1
response['msg'] = "图片上传失败!"
return JsonResponse(response)
这里要注意的是,el-upload发送的post请求中带有FILES类型的文件,通过file = request.FILES.get(‘file’)可以得到这个文件,在此基础上,file.name可以得到文件名,file.read()可以读取文件内容。
至此,我们已经可以实现 “用户选择图片->后端接收请求->后端保存图片”这些功能。图片将会如我们规定的一样保存至指定路径,如下图:
2. 显示上传的图片
但是,如果照着上面的步骤进行下去的话,大家可能发现头像并不能在前端显示出来,那是因为我们只保存了头像,而并未指定如何显示头像。这时候就要用到前端img标签中指定的路径了,刚刚我们指定的url是 <“http://127.0.0.1:8000/media/user/” + res.file>,其中res.file就是我们刚刚后端返回的新的图片名。为了与前端指定的url对应,我们也需要在后端加上对应的请求。
re_path(r'^media/user(?P<path>.*)$', serve, {'document_root': settings.USER_AVATAR_ROOT}),
这个url与普通的url不太一样,可以用来加载如图片之类的静态资源,其中media/user(?P<path>.*)与刚刚前端规定的url<“http://127.0.0.1:8000/media/user/” + res.file>相对应,而settings.USER_AVATAR_ROOT就表明,当后端接收到这个url请求后,就转而去我们指定的路径(USER_AVATAR_ROOT)中去找图片,并返回给前端。这一系列的操作都由django替我们完成,无需自己再编写views.py中的请求处理方法。
后话:可能会有小伙伴使用“直接指定本机路径”的方法来存储和显示用户头像,结果前端会报“file不安全”之类的错误,这种粗暴的方法既不优雅,也不符合Web开发的思想。说到底,把头像集中上传到指定位置、再发送请求通过后端服务器获取头像才是正解。
原文地址:https://blog.csdn.net/qq_51248362/article/details/134606165
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_11301.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!