用django做后台开发的朋友应该都会遇到图片上传这个需求,我们为了规范化管理图片在服务器的存储位置,一般都会在setting.py文件中重新配置图片的存储路径,如下图:
这是我们配置好后,图片的存储目录,如下图:一目了然,查起管理来都很方便
图片在数据库中存储数据是该图片在服务器中的路径,如下图:
然而与图片上传相比,图片的删除反而更加让人头疼。
本人在开发时也是遇到了图片删除的需求,可是并未在网上找到满意度的解决方案,无奈最初只能先写个假删,以满足需求。代码如下:
# 这是url文件中的接口
path('delete-cargo-image/', view_upload.DeleteCargoImageView.as_view()),
re_path(r'^delete-cargo-image/(?P<pk>\d+)/$', iew_upload.DeleteCargoImageView.as_view()),
# 自建删除方法
class DeleteCargoImageView(APIView):
"""
删除货物图片(假删)
"""
def delete(self, request, pk):
filtered_data = Cargo.objects.filter(id=pk).first()
filtered_data.image_path = ""
filtered_data.save()
return Response({'errCode': 0, 'errMessage': '删除成功', 'data': {}})
这个假删逻辑因该很好理解:
首先通过前台传来的id找到要删除图片的那条记录 filtered_data = Cargo.objects.filter(id=pk).first()。
然后把该条记录的image_path字段设置为空 filtered_data.image_path = ""
最后保存数据就完成了 filtered_data.save()
这样返回给前台的数据中image_path没有路径内容,因此在前台就显示不出来图片,所以也算实现了图片的删除。如果你的项目图片上传次数不多,你也不想太麻烦,这种方法是可行的。但事实上在服务器中图片并未删除,随着你上传次数的增加,图片会越来越多,对于那些超高频率上传的项目来说当然不能这样做。
前端显示没有图片
但是在服务器端会有越来越多的图片,所以这其实是非常不合理的。
最后本人在好同学的帮助下,共同专研一个多小时终于解决这个问题,实现了服务器端图片文件的删除,即真实的把这图片文件给删除。在此我要特别感谢我的这位好同学。
情到深处,撸代码,先把代码附上,如下:
class DeleteCargoImageView(APIView):
"""
删除货物图片(服务器文件删除真删)
"""
def delete(self, request, pk):
filtered_data = Cargo.objects.get(id=pk)
path = filtered_data.image_path.path # 获取图片地址
norm_path = os.path.normpath(path) # 规范化路径
# 重组路径
r_path = os.path.join(*norm_path.split(f'{os.path.sep}media{os.path.sep}', 1))
# r_path = '\\'.join(norm_path.split('\\media\\', 1)) 和上面等价
print(filtered_data.image_path.path, r_path)
os.remove(r_path)
filtered_data.image_path.delete(save=True)
return Response({'errCode': 0, 'errMessage': '删除成功', 'data': {}})
和假删一样,在删除前我们首先要拿到那个要删除图片的路径然后将其从服务器中删除,当然这个问题以及难点就出在了这里,即如何获取到正确的图片路径。
代码详解:
filtered_data = Cargo.objects.get(id=pk)
通过id获取要删除图片的当前记录相关的数据
path = filtered_data.image_path.path
获取该图片的存储路径(想了解这个路径的朋友可以打印下来看看,这也是为什么要涉及到后面的操作)
通过打印的path我们可以看到经过MEDIA_ROOT配置后,我们在获取该图片的存储路径时他会在我们的路径上给我多加一层\media\。下面是图片在我本机真实的存储路径。
看到这问题也就变简单了,只要我们能把这个多余的\media\给去掉然后在调用os.remove()方法就行了。
可是难点就出在如何把这个\media\去掉。下面便是本人提供的解决方式。
norm_path = os.path.normpath(path)
规范化路径,为什么要规范化路径,是因为路径在代码中和在系统中的实际形式是不一样的,如下图,如果我们要对这个路径进行操作,必需确保它规范统一。建议你们打印多实验几下,可能印象会更深刻。
r_path = ‘\’.join(norm_path.split(’\media\’, 1))
分割、重组路径。这一步即使对规范好的路径进行相关操作,split(‘a’, num)方法,a参数是切割依据,num是切割次数。norm_path.split(’\media\’, 1)即norm_path路径根据里面的\media\进行切割,切割一次。切割后的路径你们可以打印看一下如下两段:
G:\project_2020\tongsheng\tlms_server
\media\cargo\images
\’.join()则是将上面两段路径合并在一起,最终路径如下:
**r_path = os.path.join(*norm_path.split(f’{os.path.sep}media{os.path.sep}’, 1)) **
分割、重组路径优化。这是对上一行代码的优化。因为在linux系统文件路径和windows系统中是不同的,这种写法可以是我们无论是在windows系统还是linux系统都能正确的找到文件,而不会出错。
os.remove(r_path)
根据图片地址在服务器里删除图片。在调用os.remove()方法前,我们要先引入os模块
import os
filtered_data.image_path.delete(save=True)
最后,更新数据库将image_path里的存储路径删除。别忘了在url.py文件里配置路由接口
服务器删除图片的大功告成