如何编写一个自定义的文件存储类
如果你需要提供自定义文件储存功能——一个普通的例子是,把文件储存在远程系统中——自定义一个存储类可以完成这一任务来完成。下面是需要完成的具体步骤:
你自定义的存储系统必须为
Django.core.files.storage.Storage
的一个子类:``` from django.core.files.storage import Storage
class MyStorage(Storage): ...
```
Django 必须能以无参数实例化你的存储系统。意味着所有配置都应从
django.conf.settings
配置中获取:``` from django.conf import settings from django.core.files.storage import Storage
class MyStorage(Storage):
def __init__(self, option=None):
if not option:
option = settings.CUSTOM_STORAGE_OPTIONS
...
```
在你的存储类中,除了其他自定义的方法外,还必须实现 _open() 以及 _save() 等其他适合你的存储类的方法。关于这些方法,详情请查看下面的信息。
另外,如果你的类提供了本地文件存储,它必须重写
path()
方法。您的存储类必须是 deconstructible,以便在迁移中的字段上使用它时可以序列化。 只要你的字段有自己的参数 serializable,你可以使用
django.utils.deconstruct.deconstructible
类装饰器(这是 Django 在 FileSystemStorage 上使用的)。
默认情况下,下面的方法将引发一个 NotImplementedError
的错误,并且通常它们必须被重写:
可是,记住并非所有这些方法都是需要的,并且可能故意被省略。正因为如此,让每个方法未实现并仍然拥有一个可用储存是可能的。
举例来说,如果列出某些存储后端的内容被证明代价会很昂贵,那么您可以决定不实现 Storage.listdir()
方法。
另一个例子是只处理写入文件的后端。在这种情况下,你不需要实现上述任何方法。
最终,你决定实现这些方法中的哪一个。一些方法未实现结果会生成部分(可能会损坏的)接口。
你可能也经常会用到专为自定义存储对象设计的钩子函数。他们是:
_open
(name, mode=’rb’)
要求。
由 Storage.open()
调用,这是存储类用于打开文件的实际机制。这必须返回一个 File
对象,尽管在大多数情况下,你会想在这里返回一些实现特定于后端存储系统的逻辑的子类。当文件不存在时,应该引发 FileNotFoundError 异常。
_save
(name, content)
被称为 Storage.save()
。这个 name
会早已经历 get_valid_name()
和 get_available_name()
,并且 content
将会成为 File
对象自身。
应该返回实际保存的文件的名称(通常是传递的 name
,但如果存储需要更改文件名,则返回新名称)。
get_valid_name
(name)
返回适用于底层存储系统的文件名。 传递给此方法的 name
参数既不是发送给服务器的原始文件名,如果 upload_to
是可调用的,则在删除任何路径信息后由该方法返回的文件名。 重写此操作可以自定义如何将非标准字符转换为安全文件名。
“Storage”上提供的代码仅保留原始文件名中的字母数字字符,句点和下划线,并删除其他所有内容。
get_alternative_name
(file_root, file_ext)
将会在 file_root
和 file_ext
这两个参数的基础上返回另一个文件名。默认情况下,在执行前一个下划线再加上 7 个由字母和数字组成的字符串将将会追加到原来的文件名后。
get_available_name
(name, max_length=None)
返回存储机制中可用的文件名,可能会考虑提供的文件名。 根据上述 get_valid_name()
方法,传递给此方法的 name
参数已经被清除为一个对存储系统有效的文件名。
返回的文件名的长度不会超过 max_length
,如果该参数被提供的话。若找不到一个可用的独一无二的文件名,则抛出一个 SuspiciousFileOperation 异常。
假如已经存在名为 name
的文件,那么 get_alternative_name()
将会被调用来得到另一个替代的名称。
使用你的自定义存储引擎
使用自定义存储与 Django 的第一步是告诉 Django 你将要使用的文件存储后端。这可以通过 STORAGES 设置来完成。该设置将存储别名(这是在整个 Django 中引用特定存储的一种方式)映射到该特定存储后端的设置字典。内部字典中的设置在 STORAGES 文档中有详细描述。
然后通过别名从 django.core.files.storage.storages 字典中访问存储:
from django.core.files.storage import storages
example_storage = storages["example"]