Django图片上传到后台:使用ImageField

环境:Django2.1.1+Python3.5+Mysql5.7.27  项目:Adidas

1.HTML中的form表单上传按钮

这个东西负责前端用户选择本地文件,交给浏览器,当表单提交时,由后台接收(表单具体介绍见:)

                  

	
	

2.models.py文件的设置

前端post过来了file类型的数据,获取都明白是request.FILES.get("Pictrue"),其中Picture是文件标签的属性

那么获取后存哪儿呢?这里介绍的是利用模型(相关知识见:需要尽心数据迁移,所以必须看)的ImageField:

class Picture(models.Model):

    name = models.CharField(max_length=20,unique=True)

    pic_path = models.ImageField(upload_to='picture') #这个路径必须是相对路径,为什么,见后面

    class Meta:

        ordering = ['id']

        db_table = 'picture'      

#upload_to属性必须写,如果是相对路径,upload的值会和MEDIA_ROOT连接起来(此处有大坑),生成save时文件存放的路径。如果是绝对路径比如upload_to = '/picture/',这就是项目下的绝对路径了(比如写/picture/时,会报错,它警告我属性值不可以用绝对路径,强行运行会产生如下错误)

Django图片上传到后台:使用ImageField_第1张图片

这就是为什么强调适合MEDIA_ROOT连接的原因之一,绝对路径,直接是在项目路径之下,顶级目录,一般MEDIA_ROOT都不会是项目路径,所以连接失败了

(MEDIA_ROOT相关理解和设置见,不错,是我的另一篇博客,我牛皮:关于MEDIA_ROOT)。

将此model迁移到数据库(属于Django到Mysql的连接,详情见:)

迁移完成后,数据库会有两个字段name和pic_path,并且pic_path也是char类型的

3.接下来开始保存

post接收操作是在views.py中的,别写错地方了

from .model import Picture   #将模型倒入到views.py,注意是  .model

picture = Picture()  #生成一个对象

picture.name = request.POST.get("name")

picture.pic_path = request.FILES.get("Picture")

picture.save()  #执行此命令

save()方法执行完成,会产生两种反应

①“upload_to值+文件名”形成一个路径值保存在数据库的pic_path字段中。观察upload_to的值,我们可以看到,我们只规定了文件路径,即picture,所以文件名就是我们上传文件原有的文件名(这是我们不想要的,因为存在被覆盖的可能)。当然,我们可以把upload_to的值设置为带文件名的picture/1.jpg,后果就是,上传了100张不同的图片,只会对1.jpg重写一百次,只会保留最后一张,前面的都被覆盖了。虽然存储成功了,但这不是我们期望的。

②文件会保存在MEDIA_ROOT路径下的picture文件夹下

4.动态设置upload_to指定的路径

上面第三步,可以看出来,不论是使用原有的文件名,还是写死文件名都不是我们想要的。所以,为了避免覆盖,我们自己定义文件名,所以我们要对models.py进行更改

此外,我们要定义一个函数改变upload_to的值,upload_to接受函数作为参数值

①在tools文件夹下的function.py中我定义了以下函数

import hashlib
def getMd5(name):   #把任意长度的数据转换为一个长度固定的数据串
    if isinstance(name,str):
        name = name.encode("utf-8")
    m = hashlib.md5()
    m.update(name)
    return  m.hexdigest()

def changeName(instance ,filename ):  其中instance代表使用此函数类的一个实例,filename就是我们上传文件的文件名(为什么filename就是文件名,我只能猜测是upload_to参数规定的)
    if isinstance(filename, str): #判断name是否是str类型的一个实例
        split = filename.split('.')
        file_rename = getMd5(instance.name + split[0]) + '.' + split[1]  # 对文件名进行重编码,并规定文件读写路径
        pic_write_path = 'picture/'+file_rename
        return pic_write_path

②model改为

from tools.function import changeName
class upPicture(models.Model):
    name = models.CharField(max_length=20,unique=True)  #用户名
    pic_path = models.ImageField(upload_to=changeName)  #用户上传的图片

    class Meta:
        ordering = ['id']
        db_table = 'uppicture'

重新进行数据模型迁移  manage.py同级目录下执行

# 生成迁移文件:
# python manage.py makemigrations
# 执行迁移:
# python manage.py migrate

接下来views文件引用的就不再是Pictrue而是upPicture了,执行save,观察两种反应是否正确

结果很刺激,提示不正确,看它抛出异常的地方,会发现这是个字典,为什么呢?

Django图片上传到后台:使用ImageField_第2张图片

因为按照我的MEDIA_ROOT配置,MEDIA_ROOT就是个字典,而upload_to目录是直接和MEDIA_ROOT拼接(网上那么多复制粘贴的博客,我看了三天才终于有一个人提到了这一点,哭了),所以出现了错误。这个错误和MEDIA_URL那个解决不同,MEDIA_URL的跳转url设置写为

{'document_root': settings.MEDIA_ROOT[0]}  就可以跳过字典这个问题了,upload用这种跳不过去,因为我不知道在直接拼接的源码在哪里,那我只能用别的方法

解决办法就是,将MEDIA_ROOT设置为非字典即

MEDIA_ROOT = os.path.join(BASE_DIR,'static/media').replace("\\","/")

 #其实这里用\\Django也可以解析路径的,我换了是因为看着舒服

这样就全部OK,撒花完结

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Django)