---
title: "编写一个自定义存储系统"
version: 2.1
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/2.1/howto/custom-file-storage/
canonical: https://djangodocs.dev/zh-hans/2.1/howto/custom-file-storage/
---
# 编写一个自定义存储系统

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

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

   ```
   from django.core.files.storage import Storage

   class MyStorage(Storage):
       ...
   ```
2. Django必须能以无参数实例化你的存储系统。意味着所有设置都应从\`\`dango.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. 在你的存储类中，除了其他自定义的方法外，还必须实现  [`_open()`](#django.core.files.storage._open) 以及 [`_save()`](#django.core.files.storage._save) 方法。关于这些方法，详情请查看下面的信息。

   另外，如果你的类提供了本地文件存储，它必须重载  `path()` 方法。
4. 您的存储类必须是：ref：deconstructible，以便在迁移中的字段上使用它时可以序列化。 只要你的字段有自己的参数：ref：serializable，你可以使用django.utils.deconstruct.deconstructible类装饰器（这是Django在FileSystemStorage上使用的）

通常，下面的方法会引发一个 NotImplementedError，并通常必须被重写。

- [`Storage.delete()`](/zh-hans/2.1/ref/files/storage/#django.core.files.storage.Storage.delete)
- [`Storage.exists()`](/zh-hans/2.1/ref/files/storage/#django.core.files.storage.Storage.exists)
- [`Storage.listdir()`](/zh-hans/2.1/ref/files/storage/#django.core.files.storage.Storage.listdir)
- [`Storage.size()`](/zh-hans/2.1/ref/files/storage/#django.core.files.storage.Storage.size)
- [`Storage.url()`](/zh-hans/2.1/ref/files/storage/#django.core.files.storage.Storage.url)

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

举例来说，如果列出某些存储后端的内容会比较消耗性能，那么您可以决定不实现\`Storage.listdir\`方法。

另一个例子是只处理写入文件的后端。在这种情况下，你不需要实现上述任何方法。

最终，你决定实现这些方法中的哪一个。一些方法未实现结果会生成部分（可能会损坏的）接口。

你可能也经常会用到专为自定义存储对象设计的钩子函数。他们是：

#### `_open(name, mode='rb')`

**要求**.

它将被\`\`Storage.open()\`\`调用，前者才是存储类用来打开文件的真正机制，这个方法必须要返回一个文件对象。尽管在大多数时候，你想要这个方法返回一个继承于特定逻辑的后台存储系统的子类。

#### `_save(name, content)`

被称为\`\`Storage.save()\`\`。这个 `name` 会早已经历\`\`get\_valid\_name()\`\` 和 `get_available_name()`，并且 `content` 将会成为 File\`\`对象自身。

应该返回保存的文件名的实际名称（通常是传入“name”，但如果内存需要改变文件名，则返回新名称）。

#### `get_valid_name(name)`

返回适用于底层存储系统的文件名。 传递给此方法的\`\`name\`\`参数既不是发送给服务器的原始文件名，如果\`\`upload\_to\`\`是可调用的，则在删除任何路径信息后由该方法返回的文件名。 重写此操作可以自定义如何将非标准字符转换为安全文件名。

“Storage”上提供的代码仅保留原始文件名中的字母数字字符，句点和下划线，并删除其他所有内容。

#### `get_available_name(name, max_length=None)`

返回存储机制中可用的文件名，可能会考虑提供的文件名。 根据上述\`\`get\_valid\_name（）\`\`方法，传递给此方法的\`\`name\`\`参数已经被清除为一个对存储系统有效的文件名。

返回的文件名的长度不会超过\`\`max\_length\`\`，如果该参数被提供的话。若找不到一个可用的独一无二的文件名，则抛出一个:exc:SuspiciousFileOperation \<django.core.exceptions.SuspiciousOperation\> 异常。

如果已经存在一个 `name` 的文件，则会在扩展后缀前添加下划线和7位随机字母。
