From 52e6a7adf4e2174feaa5bfc1ea551e2d963d11c8 Mon Sep 17 00:00:00 2001 From: Fabre Florian Date: Mon, 4 Sep 2023 16:49:25 +0200 Subject: [PATCH] ModelRelatedField can have string pk and this will not work with the default datatype 'json' used in entityfilter widget. (backport 2.4) --- CHANGELOG.txt | 2 ++ creme/creme_core/forms/entity_filter/widgets.py | 9 +++++++-- .../creme_core/static/creme_core/js/widgets/dselect.js | 10 +++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 042bfec8ef..5686fcbc6c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -28,6 +28,8 @@ - The 'DynamicSelect' widget now accepts 'avoid_empty' constructor argument : when true the 'data-no-empty' attribute is enabled on client side. - Keep the actual behaviour of 'DynamicSelect' within the ChainedSelect widget definitions: - Add avoid_empty=True to all DynamicSelect having a child dependency. + # In 'creme_core.forms.entity_filter': + - ModelRelatedField can have string pk and this will not work with the default datatype 'json' used in entityfilter widget. # In Javascript : - 'creme.form.Select2' now supports the lazy loading of selections : Useful in entity filter polymorphic inputs that do not know the selected options beforehand. diff --git a/creme/creme_core/forms/entity_filter/widgets.py b/creme/creme_core/forms/entity_filter/widgets.py index 253ed4fffe..18f3e82de8 100644 --- a/creme/creme_core/forms/entity_filter/widgets.py +++ b/creme/creme_core/forms/entity_filter/widgets.py @@ -155,6 +155,10 @@ def _build_valueinput(self, field_attrs): EQUALS_OPS = f'{operators.EQUALS}|{operators.EQUALS_NOT}' add_input = pinput.add_input + # json datatype will consider pk strings as an invalid value and replaced + # by "null" + enum_field_attrs = {**field_attrs, 'datatype': 'string'} + def is_enumerable_field(field): return isinstance(field, ModelRelatedField) and ( not issubclass(field.remote_field.model, (CremeEntity, get_user_model())) @@ -171,13 +175,13 @@ def is_choices_field(field): if is_enumerable_field(field): add_input( f'^enum(__null)?.({EQUALS_OPS}).{name}$', - widget=FieldEnumerableSelect, attrs=field_attrs, + widget=FieldEnumerableSelect, attrs=enum_field_attrs, field=field, ) elif is_choices_field(field): add_input( f'^choices(__null)?.({EQUALS_OPS}).{name}$', - widget=DynamicSelectMultiple, attrs=field_attrs, + widget=DynamicSelectMultiple, attrs=enum_field_attrs, options=field.choices, ) @@ -306,6 +310,7 @@ def field_choicetype(field): return 'string' def get_context(self, name, value, attrs): + # TODO : the default datatype should be "json" only for JSONField. field_attrs = {'auto': False, 'datatype': 'json'} if self.autocomplete: diff --git a/creme/creme_core/static/creme_core/js/widgets/dselect.js b/creme/creme_core/static/creme_core/js/widgets/dselect.js index d44ebbdd19..c88685ddbe 100644 --- a/creme/creme_core/static/creme_core/js/widgets/dselect.js +++ b/creme/creme_core/static/creme_core/js/widgets/dselect.js @@ -21,6 +21,14 @@ creme.widget = creme.widget || {}; +function datatypeConverter(datatype) { + if (datatype === 'json') { + return function(data) { + return creme.widget.cleanval(data, null); + }; + } +} + creme.widget.DynamicSelect = creme.widget.declare('ui-creme-dselect', { options: { backend: undefined, // new creme.ajax.Backend({dataType:'json', sync:true}), @@ -65,7 +73,7 @@ creme.widget.DynamicSelect = creme.widget.declare('ui-creme-dselect', { _initModel: function(element, options) { var self = this; - var converter = this._converter = options.datatype === 'json' ? function(data) { return creme.widget.cleanval(data, null); } : undefined; + var converter = this._converter = datatypeConverter(options.datatype); var initial = creme.model.ChoiceGroupRenderer.parse(element, converter); this._model = new creme.model.AjaxArray(this._backend, initial);