Creación de sistema de almacenamiento personalizado¶
Si necesitas proporcionar un almacenamiento de archivos personalizado -un ejemplo común es almacenar archivos en algún sistema de archivos remoto- puedes hacerlo definiendo una clase de almacenamiento personalizada. Deberás seguir estos pasos:
Tu sistema de almacenamiento personalizado debe heredar de
django.core.files.storage.Storage
:from django.core.files.storage import Storage class MyStorage(Storage): ...
Django debe ser capaz de crear una instancia de tu sistema de almacenamiento sin pasarle argumentos. Esto significa que cualquier ajuste debe ser tomado de
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 ...
La clase de almacenamiento deberá implementar los métodos
_open()
y_save()
, junto con cualquier otro método apropiado para tu clase de almacenamiento. Observar debajo más sobre estos métodos.Adicionalmente, la clase proporciona almacenamiento local de archivos, debe redefinir el método
path()
.La clase de almacenamiento debe ser deconstruible para que pueda ser serializada al usarse en un campo en una migración. Siempre y cuando el campo tenga argumentos que sean serializables por sí mismos, puedes usar el decorador de clase
django.utils.deconstruct.deconstructible
con este propósito (es lo que Django usa en FileSystemStorage).
Por omisión, los siguientes métodos lanzan como excepción NotImplementedError por lo que deberán ser redefinidos:
Nótese sin embargo que no todos estos métodos son requeridos y pueden ser omitidos. Como suele ocurrir, es posible dejar cada método sin ser implementado y tener un Storage funcional.
Por medio de ejemplos, si listar el contenido de cierto backend de almacenamiento se vuelve costoso, puedes decidir si implementar Storage.listdir.
Otro ejemplo sería un backend que solo contemple la escritura de archivos. En este caso, no necesitarías implementar ninguno de los métodos de arriba.
Por último, la implementación de estos métodos depende de ti. Dejar algunos sin implementar darían una interfaz parcial (posiblemente rota).
You’ll also usually want to use hooks specifically designed for custom storage objects. These are:
-
_open
(name, mode='rb')¶
Requerido
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.
-
_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).
-
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.
-
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 SuspiciousFileOperation
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.