Django实战010:搭建图片服务器详解

前面我写了个简单的图片上传服务器功能:Django实战009:文件上传实现过程详解,这里只是简单的实现了图片上传、存储和访问的功能,并没有对图片进行过多的处理,导致大部分图片出现重复存储,文件名重命名等现象,所以今天来重新搭建图片服务器。

 重新定义模型类

定义模型来保存图片的基本信息,包括图片的名字、大小、类型、文件存储路径和创建时间,这里我还定义了一个Md5用来区分图片,防止重复上传相同的图片。更新时间看个人需求,我这里暂时不需要就注释掉了(我主要用来存储文章中的图片的,如果已经存在直接返回路径即可,无需更新文件)。

定义完之后记得执行迁移命令,同步至数据库:Python manage.py makemigrations 和  python manage.py migrate

class uploadImage(models.Model):
    imgName = models.CharField(max_length=252, default="" ,verbose_name="文件名")
    imgMd5 = models.CharField(max_length=128,verbose_name="MD5值")
    imgType = models.CharField(max_length=32,verbose_name="类型")
    imgSize = models.IntegerField(verbose_name="大小")
    imgPath = models.CharField(max_length=128, verbose_name="图片路径")
    imgCreated = models.CharField(max_length=64,default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),verbose_name="创建时间")
    # imgUpdated = models.CharField(max_length=64,default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),verbose_name="更新时间")

    def __str__(self):
        return self.imgName

    class Meta:
        db_table = 'uploadImage'

注意:这里更新时间我用的是CharField而非DateField,原因是使用DateField时时间格式并不是我想要的,通过strftime转换后就成了字符串,所以我直接用CharField来存了。文件路径存储用到的也不是ImageField,而是直接用CharField来存储的。 

定义路由

为视图配置访问路由,我定义了一个uploadimage,我们只要访问http://127.0.0.1:8000/uploadimage/就可以找到对应的路由了,因为这是POST请求接口,需要携带数据进行接口访问,不然就会报错,这里我们可以通过postman来模拟测试。

from django.conf.urls import url
from article import views

urlpatterns = [
    url(r'^uploadimage/$',views.uploadImg),
]

定义方法

我单独新增了一个文件tools.py来写入以下方法:包括 计算文件的md5、#文件重命名及写入、# 检测文件类型、# 限制文件大小,方便后面在视图中调用

import os, time, random,hashlib,datetime
from django.conf import settings

# 计算文件的md5
def GetFileMd5(file):
    md5Obj = hashlib.md5()
    for chunk in file.chunks():
        md5Obj.update(chunk)
    return md5Obj.hexdigest()

#文件重命名及写入
def Rename(file):
    times=time.strftime('%Y%m%d%H%M%S')
    ran=random.randint(0,1000)
    ext = os.path.splitext(file.name)[1]
    newfile="{}{}{}".format(times,ran,ext)
    path=os.path.join('media',newfile).replace('\\','/')
    read=open(path, 'wb+')
    for chunk in file.chunks():
        read.write(chunk)
    read.close()
    return  path

# 检测文件类型
def JudgeType(ext):
    ImageType = [".png", ".jpeg", ".jpg", ".gif", ".bmp"]
    if ext in ImageType:
        return True
    return False

# 限制文件大小
def FileSize(size):
    limit=settings.IMAGE_SIZE_LIMIT
    if size<limit:
        return True
    return False

定义视图 

我要实现的功能有以下几点:

1.获取文件MD5值,用来区分文件,防止重复上传相同的图片。

2.文件大小限制,一般情况下允许上传不大于5M的图片。

3.文件类型检测,判断上传文件是否为图片类型文件。

4.文件重命名,我们在上传图片的时候经常会有同名的文件,为了更好的区分我们在上传的时候对文件进行重命名操作。

5.手动上传图片文件到服务器中。

6.将信息存入到数据库中并返回图片地址给前端。

接下来我们在视图中引入,先获取前端发来的文件对象,然后计算出文件的MD5,那这个MD5去数据库中匹配,如果存在则直接将对应的图片路径返回给前端,如果没有我们就开始进行写入,写入前我们先对文件大小进行判定,再对文件类型进行判定,如果都满足的话就进行文件重命名和写入操作,最后将文件信息存入到数据库中即可。这里我提取了文件重命名之后的名称、文件类型、文件大小、文件存储路径和文件MD5值,创建时间是自动写入的无需操作。

from django.http import JsonResponse
from article import models
from article.models import uploadImage
from article.tools import *
from django.conf import settings

# Create your views here.
def uploadImg(request):
    if request.method == "POST":
        file = request.FILES.get('img')
        md5=GetFileMd5(file)
        imgobj = models.uploadImage.objects.filter(imgMd5=md5)
        if not imgobj:
            size = file.size
            if not FileSize(size):
                info = {'code': 403, 'error': '文件太大!'}
                return JsonResponse(info)
            ext = os.path.splitext(file.name)[1]
            if not JudgeType(ext):
                info = {'code': 403, 'error': '文件类型错误!'}
                return JsonResponse(info)
            path = Rename(file)
            name = os.path.basename(path)
            create=models.uploadImage.objects.create(imgName=name, imgMd5=md5,imgType=ext,imgSize=size,imgPath=path)
            url='http://'+settings.HOST_NAME +"/"+create.imgPath
            info={'code':200,'imgurl':url}
            return JsonResponse(info)
        else:
            url ='http://'+settings.HOST_NAME +"/"+imgobj.first().imgPath
            info = {'code': 200, 'imgurl': url}
            return JsonResponse(info)

接口测试

通过postman模拟POST请求来测试该接口,我们提交一个文件类型的参数进行POST访问,这里我传了一个文件名为视图桌面(26).jpg的图片文件,传输形式为form-data。下面我们可以看到视图返回的信息有两个,一个是code代码执行成功,另一个是imgurl,这时返回给前端的图片地址,前端拿到这个地址再插入到想显示的地方即可。

前端访问

在tinymce富文本中上传图片测试下该功能,将http://127.0.0.1:8000/uploadimage/该接口引入前端,获取imgurl并将imgurl传给success,这样我们就可以在富文本中插入该图片了。

// 图片上传
images_upload_handler: function (blobInfo, success, failure){
    let formData = new FormData()
    console.log(blobInfo.filename())
    formData.append('img',blobInfo.blob())
    self.$axios.post('http://127.0.0.1:8000/uploadimage/',formData)
    .then(response =>{
        console.log(response.data['imgurl'])
        if(response.data['code']==200){
            success(response.data['imgurl'])
        }else{
            failure('上传失败!')
        }
    })
  },
  // 挂载的DOM对象
  selector: `#${this.tinymceId}`,
})

 选中富文本中的图片,在Element中我们可以看到对应的标签,在img中可以看到我们后台返回的图片地址。

 你也可以拿着这个地址直接在浏览器中访问,直接在地址中输入即可访问该图片。

发现个小问题(好奇葩):

在tinymce中复制粘贴时发现的,当我直接复制图片然后在tinymce中粘贴时会提示上传失败,后台也没获取到图片,但是通过截图在粘贴就可以成功上传,如果通过图片查看器复制粘贴也能成功,但同时显示上传失败提示,后台有获取到对应的文件。看来tingymce的复制粘贴还有点小问题,需要重写了!

 欢迎关注本人的公众号:编程手札,文章也会在公众号更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ProgramNotes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值