mirror of
https://github.com/django/django.git
synced 2025-09-17 22:49:35 +00:00
Lines in the docs files were manually adjusted to conform to the 79 columns limit per line (plus newline), improving readability and consistency across the content.
141 lines
5.5 KiB
Plaintext
141 lines
5.5 KiB
Plaintext
===================================
|
|
How to write a custom storage class
|
|
===================================
|
|
|
|
.. currentmodule:: django.core.files.storage
|
|
|
|
If you need to provide custom file storage -- a common example is storing files
|
|
on some remote system -- you can do so by defining a custom storage class.
|
|
You'll need to follow these steps:
|
|
|
|
#. Your custom storage system must be a subclass of
|
|
``django.core.files.storage.Storage``::
|
|
|
|
from django.core.files.storage import Storage
|
|
|
|
|
|
class MyStorage(Storage): ...
|
|
|
|
#. Django must be able to instantiate your storage system without any
|
|
arguments. This means that any settings should be taken from
|
|
``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
|
|
...
|
|
|
|
#. Your storage class must implement the :meth:`_open` and :meth:`_save`
|
|
methods, along with any other methods appropriate to your storage class. See
|
|
below for more on these methods.
|
|
|
|
In addition, if your class provides local file storage, it must override
|
|
the ``path()`` method.
|
|
|
|
#. Your storage class must be :ref:`deconstructible
|
|
<custom-deconstruct-method>` 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 :ref:`serializable <migration-serializing>`, you can use the
|
|
``django.utils.deconstruct.deconstructible`` class decorator for this
|
|
(that's what Django uses on FileSystemStorage).
|
|
|
|
By default, the following methods raise ``NotImplementedError`` and will
|
|
typically have to be overridden:
|
|
|
|
* :meth:`Storage.delete`
|
|
* :meth:`Storage.exists`
|
|
* :meth:`Storage.listdir`
|
|
* :meth:`Storage.size`
|
|
* :meth:`Storage.url`
|
|
|
|
Note however that not all these methods are required and may be deliberately
|
|
omitted. As it happens, it is possible to leave each method unimplemented and
|
|
still have a working Storage.
|
|
|
|
By way of example, if listing the contents of certain storage backends turns
|
|
out to be expensive, you might decide not to implement ``Storage.listdir()``.
|
|
|
|
Another example would be a backend that only handles writing to files. In this
|
|
case, you would not need to implement any of the above methods.
|
|
|
|
Ultimately, which of these methods are implemented is up to you. Leaving some
|
|
methods unimplemented will result in a partial (possibly broken) interface.
|
|
|
|
You'll also usually want to use hooks specifically designed for custom storage
|
|
objects. These are:
|
|
|
|
.. method:: _open(name, mode='rb')
|
|
|
|
**Required**.
|
|
|
|
Called by ``Storage.open()``, this is the actual mechanism the storage class
|
|
uses to open the file. This must return a ``File`` object, though in most
|
|
cases, you'll want to return some subclass here that implements logic specific
|
|
to the backend storage system. The :exc:`FileNotFoundError` exception should be
|
|
raised when a file doesn't exist.
|
|
|
|
.. method:: _save(name, content)
|
|
|
|
Called by ``Storage.save()``. The ``name`` will already have gone through
|
|
``get_valid_name()`` and ``get_available_name()``, and the ``content`` will be
|
|
a ``File`` object itself.
|
|
|
|
Should return the actual name of the file saved (usually the ``name`` passed
|
|
in, but if the storage needs to change the file name return the new name
|
|
instead).
|
|
|
|
.. method:: get_valid_name(name)
|
|
|
|
Returns a filename suitable for use with the underlying storage system. The
|
|
``name`` argument passed to this method is either the original filename sent to
|
|
the server or, if ``upload_to`` is a callable, the filename returned by that
|
|
method after any path information is removed. Override this to customize how
|
|
non-standard characters are converted to safe filenames.
|
|
|
|
The code provided on ``Storage`` retains only alpha-numeric characters, periods
|
|
and underscores from the original filename, removing everything else.
|
|
|
|
.. method:: get_alternative_name(file_root, file_ext)
|
|
|
|
Returns an alternative filename based on the ``file_root`` and ``file_ext``
|
|
parameters. By default, an underscore plus a random 7 character alphanumeric
|
|
string is appended to the filename before the extension.
|
|
|
|
.. method:: get_available_name(name, max_length=None)
|
|
|
|
Returns a filename that is available in the storage mechanism, possibly taking
|
|
the provided filename into account. The ``name`` argument passed to this method
|
|
will have already cleaned to a filename valid for the storage system, according
|
|
to the ``get_valid_name()`` method described above.
|
|
|
|
The length of the filename will not exceed ``max_length``, if provided. If a
|
|
free unique filename cannot be found, a :exc:`SuspiciousFileOperation
|
|
<django.core.exceptions.SuspiciousOperation>` exception is raised.
|
|
|
|
If a file with ``name`` already exists, ``get_alternative_name()`` is called to
|
|
obtain an alternative name.
|
|
|
|
.. _using-custom-storage-engine:
|
|
|
|
Use your custom storage engine
|
|
==============================
|
|
|
|
The first step to using your custom storage with Django is to tell Django about
|
|
the file storage backend you'll be using. This is done using the
|
|
:setting:`STORAGES` setting. This setting maps storage aliases, which are a way
|
|
to refer to a specific storage throughout Django, to a dictionary of settings
|
|
for that specific storage backend. The settings in the inner dictionaries are
|
|
described fully in the :setting:`STORAGES` documentation.
|
|
|
|
Storages are then accessed by alias from the
|
|
:data:`django.core.files.storage.storages` dictionary::
|
|
|
|
from django.core.files.storage import storages
|
|
|
|
example_storage = storages["example"]
|