104 lines
4.0 KiB
Plaintext
104 lines
4.0 KiB
Plaintext
Writing a custom storage system
|
|
===============================
|
|
|
|
.. 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).
|
|
|
|
Your custom storage system may override any of the storage methods explained in
|
|
:doc:`/ref/files/storage`, but you **must** implement the following methods:
|
|
|
|
* :meth:`Storage.delete`
|
|
* :meth:`Storage.exists`
|
|
* :meth:`Storage.listdir`
|
|
* :meth:`Storage.size`
|
|
* :meth:`Storage.url`
|
|
|
|
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.
|
|
|
|
.. 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 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 the original filename sent to the
|
|
server, after having any path information 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_available_name(name)
|
|
|
|
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.
|
|
|
|
.. versionchanged:: 1.7
|
|
|
|
If a file with ``name`` already exists, an underscore plus a random 7
|
|
character alphanumeric string is appended to the filename before the
|
|
extension.
|
|
|
|
Previously, an underscore followed by a number (e.g. ``"_1"``, ``"_2"``,
|
|
etc.) was appended to the filename until an available name in the destination
|
|
directory was found. A malicious user could exploit this deterministic
|
|
algorithm to create a denial-of-service attack. This change was also made
|
|
in Django 1.6.6, 1.5.9, and 1.4.14.
|