【从EvalAI学习Django】自定义文件上传保存地址 | FileField | upload_to | deconstructible

需求

文件上传后如果不设置会使用默认名称进行保存,重复存储后会在原名称后添加_1、_2等避免重名,那么如何将文件存储名称和其在数据库的保存数据联系上是一个问题。

分析

文件字段为FileField,其特有的参数为upload_to和storage,upload_to决定文件保存地址,比如当upload_to="uploads/"时,实际地址为settings.MEDIA_ROOT/uploadsMEDIA_ROOT可以在配置文件中设置;storage为存储操作,默认的为FileStorageSystem

其中upload_to还有一种定义方式就是函数返回式定义,其原理为:FileField字段对象中存在generate_filename方法,其中就对upload_to的类型进行判断,如果是callable(self.upload_to),则传入相关参数调用重新赋值,而在FieldFile中的save方法会调用FileField中的generate_filename方法生成给storage所保存的文件地址。

FieldFileFileField是两个东西。

如官方文档中的例子:

# 定义函数user_directory_path接收两个参数。
def user_directory_path(instance, filename):
    # file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
    return 'user_{0}/{1}'.format(instance.user.id, filename)

class MyModel(models.Model):
    upload = models.FileField(upload_to=user_directory_path)

文档的例子有个问题就是模型在迁移的时候会对字段进行序列化转为migrations文件,但是这里所使用的函数返回式的定义也会被添加到迁移文件中,所以要使用deconstructible来避免这个问题,因为一旦被加入迁移文件,而迁移文件存在迭代更新的逻辑,之后更改文件存储方式则极其困难。

EvalAI实例

EvalAI中存在大量的文件字段,当文件多了起来,要对文件名称进行一定的规范才更容易管理,比如将比赛的pk作为文件名的一部分,这就让文件名更加的合理以及规范。

# 添加装饰器deconstructible避免加入迁移文件的问题
@deconstructible
class RandomFileName(object):
    def __init__(self, path):
        self.path = path

    def __call__(self, instance, filename):
    	# split ext 分离出文件后缀名
        extension = os.path.splitext(filename)[1]
        path = self.path
        # 如果传入的地址中存在id字符,则加入实例保存后的pk
        if "id" in self.path and instance.pk:
            path = self.path.format(id=instance.pk)
        # 随机生成文件地址
        filename = "{}{}".format(uuid.uuid4(), extension)
        filename = os.path.join(path, filename)
        return filename
# Model
# 模型文件中添加RandomFileName作为覆盖
... = models.FileField(upload_to=RandomFileName("..."), ...)

参考

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Dongbo X

感谢!!!!

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

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

打赏作者

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

抵扣说明:

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

余额充值