details: https://code.tryton.org/tryton/commit/90af71359399
branch: default
user: Cédric Krier <[email protected]>
date: Thu May 07 13:29:24 2026 +0200
description:
Add filename extension to Binary field
diffstat:
sao/CHANGELOG | 1 +
sao/src/view/form.js | 10 +++++++
tryton/CHANGELOG | 1 +
tryton/tryton/gui/window/view_form/view/form_gtk/binary.py | 18 ++++++++++---
trytond/CHANGELOG | 1 +
trytond/doc/ref/fields.rst | 9 +++++-
trytond/trytond/model/fields/binary.py | 4 ++-
7 files changed, 36 insertions(+), 8 deletions(-)
diffs (134 lines):
diff -r 25afe74dbf51 -r 90af71359399 sao/CHANGELOG
--- a/sao/CHANGELOG Thu May 07 13:28:19 2026 +0200
+++ b/sao/CHANGELOG Thu May 07 13:29:24 2026 +0200
@@ -1,3 +1,4 @@
+* Support filename extension for Binary field
* Use record name as fallback for filename of Binary field
* Support filters attribute for binary and image widgets
* Use search window to delete/remove records from xxx2Many widgets
diff -r 25afe74dbf51 -r 90af71359399 sao/src/view/form.js
--- a/sao/src/view/form.js Thu May 07 13:28:19 2026 +0200
+++ b/sao/src/view/form.js Thu May 07 13:29:24 2026 +0200
@@ -4595,6 +4595,12 @@
Sao.common.get_input_data(this.input_select, function(data,
filename) {
field.set_client(record, data);
if (filename_field) {
+ let ext = field.description.filename_ext
+ if (ext) {
+ if (filename.endsWith(`.${ext}`)) {
+ filename = filename.slice(0, -`.${ext}`.length);
+ }
+ }
filename_field.set_client(record, filename);
}
}, !field.get_size);
@@ -4654,6 +4660,10 @@
prm = jQuery.when(name);
}
return prm.then(name => {
+ let ext = this.field.description.filename_ext;
+ if (ext) {
+ name = `${name}.${ext}`;
+ }
Sao.common.download_file(data, name);
});
});
diff -r 25afe74dbf51 -r 90af71359399 tryton/CHANGELOG
--- a/tryton/CHANGELOG Thu May 07 13:28:19 2026 +0200
+++ b/tryton/CHANGELOG Thu May 07 13:29:24 2026 +0200
@@ -1,3 +1,4 @@
+* Support filename extension for Binary field
* Use record name as fallback for filename of Binary field
* Support filters attribute for binary and image widgets
* Use search window to delete/remove records from xxx2Many widgets
diff -r 25afe74dbf51 -r 90af71359399
tryton/tryton/gui/window/view_form/view/form_gtk/binary.py
--- a/tryton/tryton/gui/window/view_form/view/form_gtk/binary.py Thu May
07 13:28:19 2026 +0200
+++ b/tryton/tryton/gui/window/view_form/view/form_gtk/binary.py Thu May
07 13:29:24 2026 +0200
@@ -114,8 +114,10 @@
uri = unquote(uri)
self.field.set_client(self.record, url_open(uri).read())
if self.filename_field:
- self.filename_field.set_client(self.record,
- os.path.basename(urlparse(uri).path))
+ filename = os.path.basename(urlparse(uri).path)
+ if ext := self.field.attrs.get('filename_ext'):
+ filename = filename.removesuffix(os.path.extsep + ext)
+ self.filename_field.set_client(self.record, filename)
def get_data(self):
if hasattr(self.field, 'get_data'):
@@ -127,11 +129,15 @@
return data
def open_(self, widget=None):
- if not self.filename_field:
- return
- filename = self.filename_field.get(self.record)
+ filename = None
+ if self.filename_field:
+ filename = self.filename_field.get(self.record)
+ if not filename:
+ filename = self.record.rec_name()
if not filename:
return
+ if ext := self.field.attrs.get('filename_ext'):
+ filename = ''.join([filename, os.extsep, ext])
file_path = file_write(filename, self.get_data())
root, type_ = os.path.splitext(filename)
if type_:
@@ -144,6 +150,8 @@
filename = self.filename_field.get(self.record)
if not filename:
filename = self.record.rec_name()
+ if ext := self.field.attrs.get('filename_ext'):
+ filename = ''.join([filename, os.extsep, ext])
filename = file_selection(_('Save As...'), filename=filename,
action=Gtk.FileChooserAction.SAVE)
if filename:
diff -r 25afe74dbf51 -r 90af71359399 trytond/CHANGELOG
--- a/trytond/CHANGELOG Thu May 07 13:28:19 2026 +0200
+++ b/trytond/CHANGELOG Thu May 07 13:29:24 2026 +0200
@@ -1,3 +1,4 @@
+* Add filename extension to Binary field
* Add filters attribute for binary and image widgets
* Move last_user and last_modification to ResourceAccessMixin
* Add check deliverability option to validate email tool
diff -r 25afe74dbf51 -r 90af71359399 trytond/doc/ref/fields.rst
--- a/trytond/doc/ref/fields.rst Thu May 07 13:28:19 2026 +0200
+++ b/trytond/doc/ref/fields.rst Thu May 07 13:29:24 2026 +0200
@@ -552,8 +552,13 @@
Name of the field that holds the data's filename.
Default value is an empty string, which means the data has no filename (in
- this case, the filename is hidden, and the "Open" button is hidden when the
- widget is set to "image").
+ this case, the filename is hidden).
+
+.. attribute:: Binary.filename_ext
+
+ The extension to append to the :attr:`~Binary.filename`.
+
+ The default value is empty.
.. attribute:: Binary.file_id
diff -r 25afe74dbf51 -r 90af71359399 trytond/trytond/model/fields/binary.py
--- a/trytond/trytond/model/fields/binary.py Thu May 07 13:28:19 2026 +0200
+++ b/trytond/trytond/model/fields/binary.py Thu May 07 13:29:24 2026 +0200
@@ -33,8 +33,9 @@
def __init__(self, string='', help='', required=False, readonly=False,
domain=None, states=None, on_change=None,
on_change_with=None, depends=None, context=None, loading='lazy',
- filename=None, file_id=None, store_prefix=None):
+ filename=None, filename_ext=None, file_id=None, store_prefix=None):
self.filename = filename
+ self.filename_ext = filename_ext
self.file_id = file_id
self.store_prefix = store_prefix
super().__init__(string=string, help=help,
@@ -165,4 +166,5 @@
definition = super().definition(model, language)
definition['searchable'] = False
definition['filename'] = self.filename
+ definition['filename_ext'] = self.filename_ext
return definition