[FIX] web: don't fetch invisible relational fields
Relational fields with attribute 'invisible' set to true are in views because they are used in domains or contexts. In this case their relational data is useless, only their ids matter. Before this rev., their relational data was fetched anyway. More precisely, it was the case for many2ones after a default_get, and for x2manys with inline views, or without view (e.g. with widget 'many2many_tags').
This commit is contained in:
@@ -274,6 +274,24 @@ return core.Class.extend({
|
||||
field.onChange = "1";
|
||||
}
|
||||
|
||||
// the relational data of invisible relational fields should not be
|
||||
// fetched (e.g. name_gets of invisible many2ones), at least those that
|
||||
// are always invisible.
|
||||
// the invisible attribute of a field is supposed to be static ("1" in
|
||||
// general), but not totally as it may use keys of the context
|
||||
// ("context.get('some_key')"). It is evaluated server-side, and the
|
||||
// result is put inside the modifiers as a value of the '(tree_)invisible'
|
||||
// key, and the raw value is left in the invisible attribute (it is used
|
||||
// in debug mode for informational purposes).
|
||||
// this should change, for instance the server might set the evaluated
|
||||
// value in invisible, which could then be seen as static by the client,
|
||||
// and add another key in debug mode containing the raw value.
|
||||
// for now, we do an hack to detect if the value is static and retrieve
|
||||
// it from the modifiers,
|
||||
if (attrs.invisible && attrs.modifiers.match('"(?:tree_)?invisible": ?true')) {
|
||||
attrs.__no_fetch = true;
|
||||
}
|
||||
|
||||
if (!_.isEmpty(field.views)) {
|
||||
// process the inner fields_view as well to find the fields they use.
|
||||
// register those fields' description directly on the view.
|
||||
|
||||
@@ -1319,7 +1319,7 @@ var BasicModel = AbstractModel.extend({
|
||||
// find all many2one related records to be fetched
|
||||
_.each(record.getFieldNames(), function (name) {
|
||||
var field = record.fields[name];
|
||||
if (field.type === 'many2one') {
|
||||
if (field.type === 'many2one' && !record.fieldsInfo[record.viewType][name].__no_fetch) {
|
||||
var localId = (record._changes && record._changes[name]) || record.data[name];
|
||||
var relatedRecord = self.localData[localId];
|
||||
if (!relatedRecord) {
|
||||
|
||||
@@ -226,7 +226,7 @@ var MockServer = Class.extend({
|
||||
}
|
||||
_.each(modifiersNames, function (a) {
|
||||
if (node.attrs[a]) {
|
||||
var v = pyeval.py_eval(node.attrs[a]);
|
||||
var v = pyeval.py_eval(node.attrs[a]) ? true: false;
|
||||
if (inTreeView && a === 'invisible') {
|
||||
modifiers['tree_invisible'] = v;
|
||||
} else if (v || !(a in modifiers) || !_.isArray(modifiers[a])) {
|
||||
|
||||
@@ -3819,5 +3819,61 @@ QUnit.module('Views', {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('do not perform extra RPC to read invisible many2one fields', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
this.data.partner.fields.trululu.default = 2;
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<sheet>' +
|
||||
'<field name="trululu" invisible="1"/>' +
|
||||
'</sheet>' +
|
||||
'</form>',
|
||||
mockRPC: function (route, args) {
|
||||
assert.step(args.method);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
assert.verifySteps(['default_get'], "only one RPC should have been done");
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('do not perform extra RPC to read invisible x2many fields', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
this.data.partner.records[0].p = [2]; // one2many
|
||||
this.data.partner.records[0].product_ids = [37]; // one2many
|
||||
this.data.partner.records[0].timmy = [12]; // many2many
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<sheet>' +
|
||||
'<field name="p" invisible="1"/>' + // no inline view
|
||||
'<field name="product_ids" invisible="1">' + // inline view
|
||||
'<tree><field name="display_name"/></tree>' +
|
||||
'</field>' +
|
||||
'<field name="timmy" invisible="1" widget="many2many_tags"/>' + // no view
|
||||
'</sheet>' +
|
||||
'</form>',
|
||||
mockRPC: function (route, args) {
|
||||
assert.step(args.method);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
res_id: 1,
|
||||
});
|
||||
|
||||
assert.verifySteps(['read'], "only one read should have been done");
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -164,6 +164,31 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('do not perform extra RPC to read invisible many2one fields', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
this.data.foo.fields.m2o.default = 2;
|
||||
|
||||
var list = createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: '<tree editable="top">' +
|
||||
'<field name="foo"/>' +
|
||||
'<field name="m2o" invisible="1"/>' +
|
||||
'</tree>',
|
||||
mockRPC: function (route, args) {
|
||||
assert.step(_.last(route.split('/')));
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
list.$buttons.find('.o_list_button_add').click();
|
||||
assert.verifySteps(['search_read', 'default_get'], "no nameget should be done");
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('at least 4 rows are rendered, even if less data', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user