diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-11-02 18:19:03 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-11-16 17:04:41 +0100 |
commit | 64bbb0f222ccdb18d20b95d9c58c8228eca22f0b (patch) | |
tree | db7cc24e1a8d1a119cd78befac2165edbd3d6788 | |
parent | a6bd637b8bf662d12d96609c018a4e6cb048ee2a (diff) | |
download | Ishtar-64bbb0f222ccdb18d20b95d9c58c8228eca22f0b.tar.bz2 Ishtar-64bbb0f222ccdb18d20b95d9c58c8228eca22f0b.zip |
JSON types: multi valued choices
-rw-r--r-- | CHANGES-DEV.md | 3 | ||||
-rw-r--r-- | ishtar_common/forms.py | 7 | ||||
-rw-r--r-- | ishtar_common/models.py | 1 | ||||
-rw-r--r-- | ishtar_common/models_common.py | 16 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 45 |
5 files changed, 61 insertions, 11 deletions
diff --git a/CHANGES-DEV.md b/CHANGES-DEV.md index 5159f6ff0..8ada64dca 100644 --- a/CHANGES-DEV.md +++ b/CHANGES-DEV.md @@ -2,7 +2,8 @@ Ishtar changelog ================ ### Features ### -- Context record: bulk update +- Context record: bulk update relation - type +- JSON types: multi valued choices ### Bugs ### - Search: fix url for person and organization diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 31d1004c7..b92a80f42 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -136,6 +136,7 @@ JSON_VALUE_TYPES_FIELDS = { "D": (DateField, None), "B": (forms.NullBooleanField, None), "C": (widgets.Select2DynamicField, None), + "MC": (widgets.Select2DynamicMultipleField, None), } @@ -312,8 +313,10 @@ class CustomForm(BSForm): attrs["help_text"] = field["help_text"] if widget: attrs["widget"] = widget() - if field_cls == widgets.Select2DynamicField: - attrs["choices"] = cls._get_dynamic_choices(key) + if field_cls in (widgets.Select2DynamicField, + widgets.Select2DynamicMultipleField): + choices = cls._get_dynamic_choices(key) + attrs["choices"] = choices f = field_cls(**attrs) kls = "form-control" if "class" in f.widget.attrs: diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 6007cadef..0e3051e28 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -674,6 +674,7 @@ JSON_VALUE_TYPES = ( ("F", _("Float")), ("D", _("Date")), ("C", _("Choices")), + ("MC", _("Multi-choices")), ) diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py index fe8e65bb1..dc078000e 100644 --- a/ishtar_common/models_common.py +++ b/ishtar_common/models_common.py @@ -1077,12 +1077,22 @@ class JsonData(models.Model, CachedGen): q = cls.objects.filter(data__has_key=key[len("data__") :]).values_list( "data", flat=True ) + multi = False for value in q.all(): for k in splitted_key: value = value[k] - choices.add(value) - choices = [("", "")] + [(v, v) for v in sorted(list(choices))] - cache.set(cache_key, choices, settings.CACHE_SMALLTIMEOUT) + if isinstance(value, list): + multi = True + for v in value: + if v: + choices.add(v) + else: + choices.add(value) + c = [] + if not multi: + c = [("", "")] + c += [(v, v) for v in sorted(list(choices))] + cache.set(cache_key, c, settings.CACHE_SMALLTIMEOUT) return choices diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index 008925276..40df75a32 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -126,16 +126,23 @@ class Select2Media(object): return media -class Select2Dynamic(Select2Media, forms.Select): +class Select2DynamicBase(Select2Media): """ Select input using select, allowing dynamic creation. """ + MULTIPLE = False def render(self, name, value, attrs=None, choices=()): choices = choices or getattr(self, "choices", []) - if value and value not in [key for key, v in choices]: - choices.insert(1, (value, value)) - self.choices = choices + if value: + values = [value] + if self.MULTIPLE: + value = value[0] + values = value + for va in values: + if va not in [key for key, va in choices]: + choices.insert(1, (va, va)) + self.choices = choices klass = attrs and attrs.get("class") or "" klass += " " if klass else "" + "js-select2" if not attrs: @@ -161,7 +168,9 @@ class Select2Dynamic(Select2Media, forms.Select): if attrs.get("full-width", None): options.append("containerCssClass: 'full-width'") - html = super(Select2Dynamic, self).render(name, value, attrs) + if self.MULTIPLE: + options.append("multiple: 'true'") + html = super(Select2DynamicBase, self).render(name, value, attrs) html += """<script type="text/javascript"> $(document).ready(function() {{ $("#id_{}").select2({{ {} }}); @@ -172,6 +181,14 @@ class Select2Dynamic(Select2Media, forms.Select): return mark_safe(html) +class Select2Dynamic(Select2DynamicBase, forms.Select): + MULTIPLE = False + + +class Select2DynamicMultiple(Select2DynamicBase, forms.SelectMultiple): + MULTIPLE = True + + class Select2DynamicField(forms.ChoiceField): widget = Select2Dynamic @@ -190,6 +207,24 @@ class Select2DynamicField(forms.ChoiceField): return super(Select2DynamicField, self).to_python(value).strip() +class Select2DynamicMultipleField(forms.MultipleChoiceField): + widget = Select2DynamicMultiple + + def validate(self, value): + """ + Key can be added dynamically. Only check that the character " is not + used. + """ + if value and '"' in value: + raise ValidationError(_('The character " is not accepted.')) + + def to_python(self, value): + """ + Strip value + """ + return [v.strip() for v in super().to_python(value)] + + class Select2Base(Select2Media): def __init__( self, attrs=None, choices=(), remote=None, model=None, new=None, available=None |