mirror of
				https://github.com/django/django.git
				synced 2025-11-03 21:25:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			112 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			112 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
===============================
 | 
						|
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).
 | 
						|
 | 
						|
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.
 | 
						|
 | 
						|
.. 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 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_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, an underscore plus a random 7 character
 | 
						|
alphanumeric string is appended to the filename before the extension.
 |