最近在写 Desert 这个音游项目,为了不占用服务器带宽,我选择使用 COS 而不是存储在服务器本地。我的设计是不开放单独的上传接口,只让管理员登陆 Admin Site 手动创建数据库 record 并上传曲目文件。这么设计的话我们就需要使 Admin Site 的文件上传组件能被我们实现,然而这样很困难,而且不符合规范。
defsave(self, name, content, max_length=None): """ Save new content to the file specified by name. The content should be a proper File object or any Python file-like object, ready to be read from the beginning. """ # Get the proper name for the file, as it will actually be saved. if name isNone: name = content.name ifnothasattr(content, "chunks"): content = File(content, name) name = self.get_available_name(name, max_length=max_length) name = self._save(name, content) # Ensure that the name returned from the storage system is still valid. validate_file_name(name, allow_relative_path=True) return name defgenerate_filename(self, filename): """ Validate the filename by calling get_valid_name() and return a filename to be passed to the save() method. """ filename = str(filename).replace("\\", "/") # `filename` may include a path as returned by FileField.upload_to. dirname, filename = os.path.split(filename) if".."in pathlib.PurePath(dirname).parts: raise SuspiciousFileOperation( "Detected path traversal attempt in '%s'" % dirname ) return os.path.normpath(os.path.join(dirname, self.get_valid_name(filename))) defurl(self, name): """ Return an absolute URL where the file's contents can be accessed directly by a web browser. """ raise NotImplementedError("subclasses of Storage must provide a url() method")
在我们的需求中,save() 所做的是将文件上传到腾讯云 COS 上,generate_filename() 需要生成文件名,url() 则返回一个文件直链,供 302 跳转。实现代码如下: