# Django 5.2.8 documentation

# 如何编写一个自定义的文件存储类

如果你需要提供自定义文件储存功能——一个普通的例子是，把文件储存在远程系统中——自定义一个存储类可以完成这一任务来完成。下面是需要完成的具体步骤：

1. 你自定义的存储系统必须为 `Django.core.files.storage.Storage` 的一个子类:

       from django.core.files.storage import Storage

       class MyStorage(Storage): ...

2. 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
               ...

3. Your storage class must implement the `_open()` and `_save()` methods, along with any other methods appropriate to your storage class. See below for more on these methods.

   另外，如果你的类提供了本地文件存储，它必须重写 `path()` 方法。

4. Your storage class must be deconstructible so it can be serialized when it's used on a field in a migration. As long as your field has arguments that are themselves serializable, you can use the `django.utils.deconstruct.deconstructible` class decorator for this (that's what Django uses on FileSystemStorage).

默认情况下，下面的方法将引发一个 `NotImplementedError` 的错误，并且通常它们必须被重写：

- `Storage.delete()`

- `Storage.exists()`

- `Storage.listdir()`

- `Storage.size()`

- `Storage.url()`

可是，记住并非所有这些方法都是需要的，并且可能故意被省略。正因为如此，让每个方法未实现并仍然拥有一个可用储存是可能的。

举例来说，如果列出某些存储后端的内容被证明代价会很昂贵，那么您可以决定不实现 `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"]