From 0d001986ddd9a8db21c558d93c533ad335f43342 Mon Sep 17 00:00:00 2001 From: Thomas Rehn Date: Tue, 8 Nov 2016 18:10:19 +0100 Subject: [PATCH] [IMP] attachment_preview: improve performance for large files with filenames (#100) --- attachment_preview/__openerp__.py | 2 +- attachment_preview/model/ir_attachment.py | 87 +++++++++++++++-------- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/attachment_preview/__openerp__.py b/attachment_preview/__openerp__.py index fa62e146..62eda094 100644 --- a/attachment_preview/__openerp__.py +++ b/attachment_preview/__openerp__.py @@ -20,7 +20,7 @@ ############################################################################## { "name": "Preview attachments", - "version": "8.0.1.1.0", + "version": "8.0.1.2.0", "author": "Therp BV,Odoo Community Association (OCA)", "license": "AGPL-3", "complexity": "normal", diff --git a/attachment_preview/model/ir_attachment.py b/attachment_preview/model/ir_attachment.py index b00d3474..98eff341 100644 --- a/attachment_preview/model/ir_attachment.py +++ b/attachment_preview/model/ir_attachment.py @@ -18,12 +18,16 @@ # along with this program. If not, see . # ############################################################################## -import collections -import os.path -import mimetypes import base64 +import collections +import logging +import mimetypes +import os.path + from openerp.osv.orm import Model +_logger = logging.getLogger(__name__) + class IrAttachment(Model): _inherit = 'ir.attachment' @@ -32,35 +36,58 @@ class IrAttachment(Model): self, cr, uid, model, ids, binary_field, filename_field=None, context=None): result = {} - for this in self.pool[model].browse( - cr, uid, - ids if isinstance(ids, collections.Iterable) else [ids], - context=context): - if not this.id: - result[this.id] = False - continue - extension = '' - if filename_field and this[filename_field]: - filename, extension = os.path.splitext(this[filename_field]) - if not this[binary_field]: - result[this.id] = False - continue - if not extension: - try: - import magic - ms = magic.open( - hasattr(magic, 'MAGIC_MIME_TYPE') and - magic.MAGIC_MIME_TYPE or magic.MAGIC_MIME) - ms.load() + context_bin_size = dict(context or {}) + context_bin_size['bin_size'] = True + ids_to_browse = ids if isinstance(ids, collections.Iterable) \ + else [ids] + # First pass: load fields in bin_size mode to avoid loading big files + # unnecessarily. + if filename_field: + for this in self.pool[model].browse(cr, uid, ids_to_browse, + context=context_bin_size): + if not this.id: + result[this.id] = False + continue + extension = '' + if this[filename_field]: + filename, extension = os.path.splitext( + this[filename_field]) + if this[binary_field] and extension: + result[this.id] = extension + _logger.debug('Got extension %s from filename %s', + extension, this[filename_field]) + # Second pass for all attachments which have to be loaded fully + # to get the extension from the content + ids_to_browse = [_id for _id in ids_to_browse if _id not in result] + for this in self.pool[model].browse(cr, uid, ids_to_browse, + context=context): + try: + import magic + ms = magic.open( + hasattr(magic, 'MAGIC_MIME_TYPE') and + magic.MAGIC_MIME_TYPE or magic.MAGIC_MIME) + ms.load() + if model == self._name and binary_field == 'datas'\ + and this.store_fname: + mimetype = ms.file( + this._full_path(this.store_fname)) + _logger.debug('Magic determined mimetype %s from file %s', + mimetype, this.store_fname) + else: mimetype = ms.buffer( base64.b64decode(this[binary_field])) - except ImportError: - (mimetype, encoding) = mimetypes.guess_type( - 'data:;base64,' + this[binary_field], strict=False) - extension = mimetypes.guess_extension( - mimetype.split(';')[0], strict=False) - - result[this.id] = (extension or '').lstrip('.').lower() + _logger.debug('Magic determined mimetype %s from buffer', + mimetype) + except ImportError: + (mimetype, encoding) = mimetypes.guess_type( + 'data:;base64,' + this[binary_field], strict=False) + _logger.debug('Mimetypes guessed type %s from buffer', + mimetype) + extension = mimetypes.guess_extension( + mimetype.split(';')[0], strict=False) + result[this.id] = extension + for _id in result: + result[_id] = (result[_id] or '').lstrip('.').lower() return result if isinstance(ids, collections.Iterable) else result[ids] def get_attachment_extension(self, cr, uid, ids, context=None):