在 Odoo 9 中一次上传多个附件
Upload multiple attachment at once in Odoo 9
我正在尝试在 Odoo 中创建一个功能,允许用户从附件表单上传多个文件,当他提交时,它会创建与所选文档一样多的附件。
我为 'binary' 字段创建了一个允许多选的小部件(在 Qweb 模板中向 'input' 标记添加 'multiple' 参数),但此时我努力创建附件并link将它们与 JS 的相关字段结合起来。
我的小部件:
odoo.define('lettermgmt', function(require)
{
'use strict';
var core = require('web.core');
var FieldBinaryFile = core.form_widget_registry.get('binary');
var FieldBinaryMultipleFiles = FieldBinaryFile.extend({
template : 'FieldBinaryMultipleFiles',
});
core.form_widget_registry.add('binary_multiple_files',FieldBinaryMultipleFiles);
});
我的第一个猜测是重写 on_file_change
方法,循环“e.target.files
”并对“/web/binary/upload_attachment
”上的每个文件发出 POST 请求。这会创建附件,但我不知道如何将它们 link 添加到我的模型(关系字段)。
我将不胜感激:)
我终于找到了解决办法:
想法是创建一个具有特定行为的自定义字符小部件。
JS代码在这里:
odoo.define('cutom_module', function(require)
{
'use strict';
var core = require('web.core');
var Char = core.form_widget_registry.get('char');
var import_button = Char.extend({
template : "import_button",
events : {
'change' : 'import_files',
},
init : function(){
this._super.apply(this,arguments);
this._start = null;
},
start : function() {
},
import_files : function(event){
var self = this;
var files = event.target.files; // Get Selected files
var attachment_ids = self.getParent().fields[ 'attachment_ids' ]; // Get existing attachments
var data64 = null;
var values_list = [];
_.each(files, function(file){
// Check if the file is already in the attachments, must specify field name here :/
if(self.already_attached(attachment_ids.get_value(),file.name)){
return;
}
var filereader = new FileReader();
filereader.readAsDataURL(file);
filereader.onloadend = function(upload) {
var data = upload.target.result;
data64 = data.split(',')[1];
var values = {
'name' : file.name,
'type' : 'binary',
'datas' : data64,
};
values_list.push([ 0, 0, values]);
if(values_list.length == files.length){
attachment_ids.set_value(values_list);
}
};
});
},
already_attached : function (attachments,filename) {
for(var i=0;i<attachments.length;i++){
if(attachments[i][2]['name'] == filename){
return true;
}
}
return false;
},
});
core.form_widget_registry.add('import_button',import_button);
});
Qweb import_button 模板:
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="HiddenInputMultipleFiles">
<div t-attf-class="oe_hidden_input_file #{fileupload_class or ''}" t-att-style="fileupload_style">
<form class="o_form_binary_form" t-att-target="fileupload_id"
method="post" enctype="multipart/form-data" t-att-action="'/web/binary/upload_attachment'">
<input type="hidden" name="csrf_token" t-att-value="csrf_token"/>
<input type="hidden" name="session_id" value="" t-if="widget.session.override_session"/>
<input type="hidden" name="callback" t-att-value="fileupload_id"/>
<t t-raw="0"/>
<input type="file" class="o_form_input_file" name="ufile" t-if="widget.widget!='image'" multiple="multiple"/>
<input type="file" class="o_form_input_file" name="ufile" accept="image/*" t-if="widget.widget=='image'"/>
</form>
<iframe t-att-id="fileupload_id" t-att-name="fileupload_id" style="display: none"/>
</div>
</t>
<div t-name="import_button" t-attf-class="base #{cls}" class="oe_web_example">
<p>
<t t-call="HiddenInputMultipleFiles">
</t>
</p>
</div>
</templates>
查看:
....
<field name="import_files" widget="import_button"/>
<field name="attachment_ids" widget="one2many_list"
>
<tree create="0">
<field name="name" string="File name"/>
</tree>
</field>
....
和模型:
....
attachment_ids = fields.Many2many(comodel_name="ir.attachment",string="Documents")
import_files = fields.Char(string=" ")
....
如果您有任何问题或改进建议,请告诉我:)
让默认提交处理 1 个文件和额外文件的自定义代码似乎也有效。
openerp.web_natuurpunt_multi_attach = function (session) {
var QWeb = session.web.qweb;
var _t = session.web._t;
session.web.Sidebar.include({
on_attachment_changed: function (event) {
var self = this;
var session_id = this.session.session_id
this.$el.find('form.oe_form_binary_form').bind('submit', function (e, data) {
var form = e.currentTarget;
var multipleFiles = form.querySelector('input[type=file]');
if (multipleFiles.files.length > 1) {
var callback = form.querySelector('input[name=callback]').defaultValue;
var model = form.querySelector('input[name=model]').defaultValue;
var id = form.querySelector('input[name=id]').defaultValue
const slicedFileList = Object.keys(multipleFiles.files)
.slice(0,multipleFiles.files.length - 1)
.reduce((result, key) => {
result[key] = multipleFiles.files[key];
return result;
}, {});
_.each(slicedFileList, function(file){
var queryData = new FormData();
queryData.append('session_id', session_id);
queryData.append('callback', callback);
queryData.append('ufile', file);
queryData.append('model', model);
queryData.append('id', id);
var request = new XMLHttpRequest();
// do the request using form info
request.open(form.method, form.action);
// want to distinguish from non-JS submits?
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
request.send(queryData);
});
}
});
self._super(event);
},
});
}
我正在尝试在 Odoo 中创建一个功能,允许用户从附件表单上传多个文件,当他提交时,它会创建与所选文档一样多的附件。
我为 'binary' 字段创建了一个允许多选的小部件(在 Qweb 模板中向 'input' 标记添加 'multiple' 参数),但此时我努力创建附件并link将它们与 JS 的相关字段结合起来。
我的小部件:
odoo.define('lettermgmt', function(require)
{
'use strict';
var core = require('web.core');
var FieldBinaryFile = core.form_widget_registry.get('binary');
var FieldBinaryMultipleFiles = FieldBinaryFile.extend({
template : 'FieldBinaryMultipleFiles',
});
core.form_widget_registry.add('binary_multiple_files',FieldBinaryMultipleFiles);
});
我的第一个猜测是重写 on_file_change
方法,循环“e.target.files
”并对“/web/binary/upload_attachment
”上的每个文件发出 POST 请求。这会创建附件,但我不知道如何将它们 link 添加到我的模型(关系字段)。
我将不胜感激:)
我终于找到了解决办法:
想法是创建一个具有特定行为的自定义字符小部件。 JS代码在这里:
odoo.define('cutom_module', function(require)
{
'use strict';
var core = require('web.core');
var Char = core.form_widget_registry.get('char');
var import_button = Char.extend({
template : "import_button",
events : {
'change' : 'import_files',
},
init : function(){
this._super.apply(this,arguments);
this._start = null;
},
start : function() {
},
import_files : function(event){
var self = this;
var files = event.target.files; // Get Selected files
var attachment_ids = self.getParent().fields[ 'attachment_ids' ]; // Get existing attachments
var data64 = null;
var values_list = [];
_.each(files, function(file){
// Check if the file is already in the attachments, must specify field name here :/
if(self.already_attached(attachment_ids.get_value(),file.name)){
return;
}
var filereader = new FileReader();
filereader.readAsDataURL(file);
filereader.onloadend = function(upload) {
var data = upload.target.result;
data64 = data.split(',')[1];
var values = {
'name' : file.name,
'type' : 'binary',
'datas' : data64,
};
values_list.push([ 0, 0, values]);
if(values_list.length == files.length){
attachment_ids.set_value(values_list);
}
};
});
},
already_attached : function (attachments,filename) {
for(var i=0;i<attachments.length;i++){
if(attachments[i][2]['name'] == filename){
return true;
}
}
return false;
},
});
core.form_widget_registry.add('import_button',import_button);
});
Qweb import_button 模板:
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="HiddenInputMultipleFiles">
<div t-attf-class="oe_hidden_input_file #{fileupload_class or ''}" t-att-style="fileupload_style">
<form class="o_form_binary_form" t-att-target="fileupload_id"
method="post" enctype="multipart/form-data" t-att-action="'/web/binary/upload_attachment'">
<input type="hidden" name="csrf_token" t-att-value="csrf_token"/>
<input type="hidden" name="session_id" value="" t-if="widget.session.override_session"/>
<input type="hidden" name="callback" t-att-value="fileupload_id"/>
<t t-raw="0"/>
<input type="file" class="o_form_input_file" name="ufile" t-if="widget.widget!='image'" multiple="multiple"/>
<input type="file" class="o_form_input_file" name="ufile" accept="image/*" t-if="widget.widget=='image'"/>
</form>
<iframe t-att-id="fileupload_id" t-att-name="fileupload_id" style="display: none"/>
</div>
</t>
<div t-name="import_button" t-attf-class="base #{cls}" class="oe_web_example">
<p>
<t t-call="HiddenInputMultipleFiles">
</t>
</p>
</div>
</templates>
查看:
....
<field name="import_files" widget="import_button"/>
<field name="attachment_ids" widget="one2many_list"
>
<tree create="0">
<field name="name" string="File name"/>
</tree>
</field>
....
和模型:
....
attachment_ids = fields.Many2many(comodel_name="ir.attachment",string="Documents")
import_files = fields.Char(string=" ")
....
如果您有任何问题或改进建议,请告诉我:)
让默认提交处理 1 个文件和额外文件的自定义代码似乎也有效。
openerp.web_natuurpunt_multi_attach = function (session) {
var QWeb = session.web.qweb;
var _t = session.web._t;
session.web.Sidebar.include({
on_attachment_changed: function (event) {
var self = this;
var session_id = this.session.session_id
this.$el.find('form.oe_form_binary_form').bind('submit', function (e, data) {
var form = e.currentTarget;
var multipleFiles = form.querySelector('input[type=file]');
if (multipleFiles.files.length > 1) {
var callback = form.querySelector('input[name=callback]').defaultValue;
var model = form.querySelector('input[name=model]').defaultValue;
var id = form.querySelector('input[name=id]').defaultValue
const slicedFileList = Object.keys(multipleFiles.files)
.slice(0,multipleFiles.files.length - 1)
.reduce((result, key) => {
result[key] = multipleFiles.files[key];
return result;
}, {});
_.each(slicedFileList, function(file){
var queryData = new FormData();
queryData.append('session_id', session_id);
queryData.append('callback', callback);
queryData.append('ufile', file);
queryData.append('model', model);
queryData.append('id', id);
var request = new XMLHttpRequest();
// do the request using form info
request.open(form.method, form.action);
// want to distinguish from non-JS submits?
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
request.send(queryData);
});
}
});
self._super(event);
},
});
}