这个东西负责前端用户选择本地文件,交给浏览器,当表单提交时,由后台接收(表单具体介绍见:)
前端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/时,会报错,它警告我属性值不可以用绝对路径,强行运行会产生如下错误)
这就是为什么强调适合MEDIA_ROOT连接的原因之一,绝对路径,直接是在项目路径之下,顶级目录,一般MEDIA_ROOT都不会是项目路径,所以连接失败了
(MEDIA_ROOT相关理解和设置见,不错,是我的另一篇博客,我牛皮:关于MEDIA_ROOT)。
将此model迁移到数据库(属于Django到Mysql的连接,详情见:)
迁移完成后,数据库会有两个字段name和pic_path,并且pic_path也是char类型的
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,观察两种反应是否正确
结果很刺激,提示不正确,看它抛出异常的地方,会发现这是个字典,为什么呢?
因为按照我的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,撒花完结