OdooWiki OCA HUB
Sin categoría Licencia: LGPL-3

Si necesita vincular algunos modelos específicos a una carpeta específica en un sistema de archivos externo y poder gestionar el contenido de esta carpeta desde la vista de formulario del modelo, este módulo es para usted.

Traducción automática al español (DeepSeek) de la descripción original de OCA, que está en inglés.

auto_awesome Qué hace este módulo

Generado por IA a partir del código · Odoo 19.0

Vincula carpetas de sistemas de archivos externos a cualquier registro de Odoo y gestiona su contenido directamente desde la vista de formulario del registro. Los usuarios pueden explorar, subir, renombrar, copiar, mover, eliminar y previsualizar archivos almacenados en almacenamientos externos sin salir de Odoo.

Este módulo añade un nuevo tipo de campo llamado External Folder (fs_folder) que se puede añadir a cualquier modelo de Odoo. Cuando se coloca un campo de este tipo en un formulario, muestra un explorador de archivos donde los usuarios pueden ver el contenido de la carpeta, abrir subcarpetas y trabajar con archivos almacenados en un sistema de archivos externo configurado mediante fs.storage.

Desde la vista de formulario los usuarios pueden: - Subir archivos arrastrando y soltando o mediante el botón de subida. - Crear nuevas subcarpetas, renombrar, copiar, cortar, pegar y eliminar archivos o carpetas. - Previsualizar los archivos compatibles en un iframe y descargarlos. - Inicializar la carpeta para el registro, desvincularla (manteniendo la carpeta en el almacenamiento externo) o eliminarla (borrándola del almacenamiento externo).

En la pantalla de configuración del almacenamiento (fs.storage) una nueva sección "Filesystem contents" permite a los administradores marcar un almacenamiento como predeterminado para el contenido de carpetas externas, y habilitar la sanitización automática de nombres de archivos y carpetas con un carácter de reemplazo para caracteres no válidos. Solo un almacenamiento puede ser el predeterminado.

El módulo también añade notificaciones en tiempo real: cuando se modifica una carpeta, los demás usuarios que están viendo el mismo registro reciben una notificación a través del bus y la lista de archivos se actualiza automáticamente. Los derechos de acceso se comprueban en el registro antes de cualquier operación de lectura o escritura sobre la carpeta. Un controlador sirve las previsualizaciones y descargas de archivos mediante URLs seguras.

Depende de

Modelos y campos (4)
  • fs.storage · amplía un modelo existentesanitize_fs_name, use_as_default_for_fs_contents, fs_name_sanitization_replace_char
  • ir.model.fields · amplía un modelo existentettype
  • fs.folder.field.web.api · modelo nuevo
  • fs.folder.field.value.adapter · modelo nuevo

Texto generado por IA (DeepSeek) al leer el código de la versión 19.0 en GitHub; puede contener errores, así que verifícalo en el código antes de decidir. El módulo es muy grande y solo se ha leído una parte del código. Ver el código en GitHub

Disponibilidad por versión

Revisado: 2026-11-03
Confirmado (verificado en repositorio y rama) Estimado (sin verificar) Sin información

Estado de confirmación: 2 confirmadas, 7 sin información de 9 versiones.

terminal Instalación y uso

Documentación de OCA · Odoo 19.0

El módulo es un módulo técnico que proporciona un nuevo tipo de campo a Odoo. No está pensado para ser utilizado directamente por los usuarios finales. Está pensado para ser utilizado por desarrolladores para crear nuevos módulos que necesiten gestionar archivos en un sistema de archivos externo.

El tipo de campo FsFolder es un tipo de campo especializado que se puede utilizar en cualquier modelo de Odoo. Cuando un desarrollador de Odoo declara un campo de este tipo en un modelo y la vista de formulario relacionada, el campo mostrará un widget especializado que permite al usuario interactuar con una carpeta en un sistema de archivos externo.

El campo está vinculado a un backend de sistema de archivos que debe configurarse en Odoo. La configuración del backend está disponible en el menú 'Settings' -> 'Technical' -> 'FS Storage'. Es posible definir un backend predeterminado para todos los campos de este tipo en la configuración de Odoo o definir un backend específico para cada modelo o campo.

En la siguiente documentación, veremos:

  • cómo declarar un campo de este tipo en un modelo
  • cómo se gestiona la seguridad
  • cómo puedes interactuar con el sistema de archivos
  • cómo puedes personalizar el comportamiento del campo

Declaración del campo

Para declarar un campo de este tipo en un modelo, necesitas importar el tipo de campo y declararlo en la definición del modelo. Por defecto, la declaración del campo no requiere ningún parampeter.

from odoo import models
from odoo.addons.fs_folder import fields as fs_fields

class MyModel(models.Model):
    _name = 'my.model'

    fs_folder_field = fs_fields.FsFolder()

El nuevo tipo de campo viene con una forma específica de inicializar el campo. Aunque el campo aún no esté inicializado, el valor del campo será una instancia de la clase FsFolderValue. Pero al igual que con los recordsets vacíos en Odoo, el valor se considerará como False en un contexto booleano o None en un contexto nulo.

from odoo.addons.fs_folder.fields import FsFolderValue

record = self.env['my.model'].create({})
assert isinstance(record.fs_folder_field, FsFolderValue)
assert not record.fs_folder_field
assert record.fs_folder_field is None

Para inicializar el campo, puedes llamar al método initialize sobre el valor del campo. Este método creará la carpeta en el sistema de archivos si aún no existe.

record.fs_folder_field.initialize()

La creación de la carpeta en el sistema de archivos requiere 2 informaciones:

  • La ruta donde se creará la carpeta
  • El nombre de la carpeta

Por defecto, la ruta es la carpeta raíz del sistema de archivos. En algunos casos, es posible que quieras crear la carpeta en una subcarpeta específica del sistema de archivos dependiendo de los datos del registro (o no). En este caso, puedes definir en la definición del campo un método que se llamará para obtener la ruta donde se creará la carpeta.

import fsspec

class MyModel(models.Model):
    _name = 'my.model'

    fs_folder_field = fs_fields.FsFolder(
        create_parent_get='get_folder_path',
    )

    def get_folder_path(self, fs: fsspec.AbstractFileSystem) -> dict[int, list[str]]:
        result = {}
        for record in self:
            result[record.id] = ['my', 'subfolder']
        return result

En este ejemplo, se llamará al método get_folder_path para obtener la ruta donde se creará la carpeta. El método debe devolver un diccionario donde la clave es el id del registro y el valor es una lista de cadenas que representan la ruta donde se creará la carpeta. (La lista de cadenas se unirá con el separador approprisate definido por el sistema de archivos específico utilizado para crear la carpeta).

De la misma manera, puedes definir un método para obtener el nombre de la carpeta (por defecto el nombre de la carpeta es el nombre para mostrar del registro).

class MyModel(models.Model):
    _name = 'my.model'

    reference = fields.Char(required=True)

    fs_folder_field = fs_fields.FsFolder(
        create_name_get='get_folder_name',
    )

    def get_folder_name(self, fs: fsspec.AbstractFileSystem) -> dict[int, str]:
        result = {}
        for record in self:
            result[record.id] = record.reference
        return result

En este ejemplo, se llamará al método get_folder_name para obtener el nombre de la carpeta. El método debe devolver un diccionario donde la clave es el id del registro y el valor es el nombre de la carpeta.

Para casos de uso avanzados, también puedes definir el método que garantizará la creación de la carpeta en el sistema de archivos y asignará el valor al campo. Este método debe devolver una lista de FsFolderValue.

class MyModel(models.Model):
    _name = 'my.model'

    reference = fields.Char(required=True)

    fs_folder_field = fs_fields.FsFolder(
        create_get='create_folder',
    )

    def create_folder(self, fs: fsspec.AbstractFileSystem) -> list[FsFolderValue]:
        result = []
        value_adapter = self.env["fs.folder.field.value.adapter"]
        storage_code = self.env[
                "fs.storage"
            ].get_default_storage_code_for_fs_content(self._name, 'fs_folder_field')
        for record in self:
            path = f'my/subfolder/{record.reference}'
            fs.mkdir(path)
            record.fs_folder_field = value_adapter._created_folder_name_to_stored_value(
                path, storage_code, fs
            )
            result.append(record.fs_folder_field)
        return result

Por último, pero no menos importante, hay disponibles 2 hooks de método adicionales para personalizar el comportamiento del campo:

  • create_additional_kwargs_get: Se llamará a este método para obtener argumentos de palabra clave adicionales que pasar al método fs.mkdir al crear la carpeta.
  • create_post_process: Se llamará a este método después de la creación de la carpeta para realizar algún procesamiento adicional.

Seguridad

> Importante: La seguridad del campo debe ser gestionada por el backend del sistema de archivos.

En el código python

La inicialización del valor del campo solo se permite si el usuario tiene acceso de escritura al registro. Desde el valor del campo, el usuario puede obtener acceso al cliente del sistema de archivos e interactuar con el sistema de archivos. El sistema de archivos tiene su raíz en la propia carpeta. El usuario solo puede interactuar con la carpeta y sus hijos sin poder subir en el sistema de archivos.

En la vista de formulario a través del widget

El addon viene con un widget específico que se utilizará para mostrar el campo en la vista de formulario. El widget mostrará el contenido de la carpeta y permitirá al usuario interactuar con ella. El usuario puede crear, eliminar, renombrar, descargar y subir archivos y carpetas. El usuario también puede navegar por el sistema de archivos. Todas estas operaciones se ponen a disposición mediante métodos proporcionados por el modelo abstracto 'fs.folder.field.web.api'. Un primer nivel de seguridad lo proporciona esta API. Cualquier operación que modifique el sistema de archivos se permitirá solo si el usuario tiene acceso de escritura al registro y cualquier operación de lectura del sistema de archivos se permitirá solo si el usuario tiene acceso de lectura al registro.

Interactuar con el sistema de archivos

Para interactuar con el sistema de archivos puedes simplemente usar el cliente del sistema de archivos proporcionado por el valor del campo.

record.fs_folder_field.fs.mkdir('my/subfolder')
with record.fs_folder_field.fs.open('my/subfolder/myfile.txt', 'w') as f:
    f.write('Hello, world!')

La api también proporciona métodos de alto nivel para interactuar con el sistema de archivos y facilitar el acceso a los archivos. Por ejemplo, si necesitas proporcionar un enlace de descarga a un archivo, puedes usar el método get_url_for_download del modelo abstracto 'fs.folder.field.web.api'.

api = self.env['fs.folder.field.web.api']
url = api.get_url_for_download(record.id,  record._name, "fs_folder_field", 'my/subfolder/myfile.txt')

Personalizar el comportamiento del campo

Como se especificó anteriormente, puedes definir algunos métodos para personalizar el comportamiento del campo. Durante el proceso de creación de un directorio en un sistema de archivos, entra en juego 1 mecanismo adicional para garantizar la conformidad del directorio creado.

Conformidad del nombre de la carpeta

Cuando se trata de crear una carpeta en el sistema de archivos, debemos evitar el uso de caracteres especiales que podrían causar problemas. Esto lo hace por defecto el campo al crear la carpeta reemplazando los caracteres que no están permitidos por el sistema de archivos por un guion bajo. Puedes controlar este comportamiento en la vista de formulario 'fs.storage'. Hay un campo disponible para deshabilitar este comportamiento y otro para definir el carácter que se utilizará como reemplazo. Si el comportamiento está deshabilitado, el campo generará un error si el nombre de la carpeta no es conforme. (Esto se aplica a la ruta completa de la carpeta).

Otras personalizaciones

Además puedes:

  • sobrescribir el adaptador que se utilizará para convertir el valor del campo a un valor almacenado y viceversa. El adaptador es un modelo que debe extender el modelo abstracto 'fs.folder.field.value.adapter'.
  • extender/sobrescribir el modelo api utilizado por el widget para interactuar con el sistema de archivos. El modelo api debe extender el modelo abstracto 'fs.folder.field.web.api'.
  • extender/sobrescribir el propio widget

Traducción automática al español (DeepSeek) de la documentación original de OCA; los comandos y el código no se traducen. Sin información verificada en OCA: Instalación, Configuración.

info

Datos importados de GitHub: esta ficha refleja la última revisión del catálogo, no una consulta en directo. Verifica siempre en la documentación del módulo y en staging antes de instalar en producción.