diff options
| author | Étienne Loks <etienne.loks@iggdrasil.net> | 2026-04-01 12:37:31 +0200 |
|---|---|---|
| committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2026-04-01 12:37:31 +0200 |
| commit | 1c4f2610c5003e24dc2a695290e54b1c931abdc2 (patch) | |
| tree | 464359ef144196cf1d8da29de1c9f4f113bb099d | |
| parent | 32f5c7fc925e0dce5dfcca35383dd52ae766bfee (diff) | |
| download | Ishtar-1c4f2610c5003e24dc2a695290e54b1c931abdc2.tar.bz2 Ishtar-1c4f2610c5003e24dc2a695290e54b1c931abdc2.zip | |
✨ general management of filter on types - filter qualification types for actors
| -rw-r--r-- | archaeological_finds/models_finds.py | 2 | ||||
| -rw-r--r-- | archaeological_operations/forms.py | 2 | ||||
| -rw-r--r-- | ishtar_common/forms.py | 17 | ||||
| -rw-r--r-- | ishtar_common/models.py | 5 | ||||
| -rw-r--r-- | ishtar_common/models_common.py | 20 | ||||
| -rw-r--r-- | ishtar_common/widgets.py | 14 |
6 files changed, 46 insertions, 14 deletions
diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py index 9b4156a9d..b57002532 100644 --- a/archaeological_finds/models_finds.py +++ b/archaeological_finds/models_finds.py @@ -207,6 +207,7 @@ class TreatmentType(HierarchicalType): initial=None, force=False, full_hierarchy=False, + limit=None ): types = super(TreatmentType, cls).get_types( dct=dct, @@ -217,6 +218,7 @@ class TreatmentType(HierarchicalType): initial=initial, force=force, full_hierarchy=full_hierarchy, + limit=limit ) if dct and not exclude: rank = 0 diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index 82f41c089..a96ce7c63 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -1343,7 +1343,7 @@ class SiteForm(CustomForm, ManageOldType): required=False) actor = widgets.Select2MultipleField( model=QualifiedBiographicalNote, label=_("Actors"), required=False, - remote=True, new=True) + remote=True, new=True, remote_filter='qualification_type__S-A') collaborator = widgets.Select2MultipleField( model=Person, label=_("Collaborators"), required=False, remote=True, new=True) diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 4db6a138b..416a1a9ec 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -707,8 +707,8 @@ class FieldType: self.empty_first = empty_first self.help_text = help_text - def get_choices(self, initial=None): - args = {"empty_first": self.empty_first, "initial": initial} + def get_choices(self, initial=None, limit=None): + args = {"empty_first": self.empty_first, "initial": initial, "limit": limit} if self.extra_args: args.update(self.extra_args) return self.model.get_types(**args) @@ -848,10 +848,14 @@ class IshtarForm(BSForm, forms.Form): for field in type_lst: self._init_type(field) - def _init_type(self, field): + def _init_type(self, field, extra=None): if field.key not in self.fields: return - self.fields[field.key].choices = field.get_choices() + if not extra: + extra = {} + if hasattr(self, "limits") and field.key in self.limits: + extra["limit"] = self.limits[field.key] + self.fields[field.key].choices = field.get_choices(**extra) if not getattr(field, "help_text", True): return self.fields[field.key].help_text = field.get_help() @@ -1349,10 +1353,7 @@ class ManageOldType(IshtarForm): if field.key not in self.fields: return initial = self.init_data.getlist(field.key) - self.fields[field.key].choices = field.get_choices( - initial=initial - ) - self.fields[field.key].help_text = field.get_help() + super()._init_type(field, extra={"initial": initial}) class QAForm(CustomForm, ManageOldType): diff --git a/ishtar_common/models.py b/ishtar_common/models.py index e52d210a6..d9923b04d 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -4702,6 +4702,10 @@ class QualifiedBiographicalNoteType(OrderedHierarchicalType): ordering = ["order", "label"] ADMIN_SECTION = _("Directory") + @classmethod + def _set_limit(cls, dct, limit): + dct["model__in"] = limit + post_save.connect(post_save_cache, sender=QualifiedBiographicalNoteType) post_delete.connect(post_save_cache, sender=QualifiedBiographicalNoteType) @@ -6200,6 +6204,7 @@ class OperationType(GeneralType): empty_first=True, default=None, initial=None, + limit=None ): dct = dct or {} exclude = exclude or [] diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py index ba27b3bbc..117981e79 100644 --- a/ishtar_common/models_common.py +++ b/ishtar_common/models_common.py @@ -403,6 +403,7 @@ class GeneralType(Cached, models.Model): initial=None, force=False, full_hierarchy=False, + limit=None ): if not dct: dct = {} @@ -412,7 +413,8 @@ class GeneralType(Cached, models.Model): if not instances and empty_first and not default: types = [("", "--")] types += cls._pre_get_types( - dct, instances, exclude, default, force, get_full_hierarchy=full_hierarchy + dct, instances, exclude, default, force, get_full_hierarchy=full_hierarchy, + limit=limit ) if not initial: return types @@ -421,6 +423,13 @@ class GeneralType(Cached, models.Model): return types @classmethod + def _set_limit(cls, dct, limit): + """ + Translate limit set in forms to a query filter + """ + raise NotImplementedError(f"_set_limit method must be set for {cls}") + + @classmethod def _pre_get_types( cls, dct=None, @@ -429,6 +438,7 @@ class GeneralType(Cached, models.Model): default=None, force=False, get_full_hierarchy=False, + limit=None ): if not dct: dct = {} @@ -439,11 +449,15 @@ class GeneralType(Cached, models.Model): if not instances: keys = ["__get_types"] keys += ["{}".format(ex) for ex in exclude] + ["{}".format(default)] + if limit: + keys.append("lim" + ";".join(limit)) keys += ["{}-{}".format(str(k), dct[k]) for k in dct] cache_key, value = get_cache(cls, keys) if value and not force: return value base_dct = dct.copy() + if limit: + cls._set_limit(base_dct, limit) if hasattr(cls, "parent"): if not cache_key: return cls._get_parent_types( @@ -467,7 +481,9 @@ class GeneralType(Cached, models.Model): return vals if not cache_key: - return cls._get_types(base_dct, instances, exclude=exclude, default=default) + return cls._get_types( + base_dct, instances, exclude=exclude, default=default + ) vals = [ v for v in cls._get_types( diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index b11ae0c5d..304e6a669 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -232,12 +232,16 @@ class Select2DynamicMultipleField(forms.MultipleChoiceField): class Select2Base(Select2Media): def __init__( - self, attrs=None, choices=(), remote=None, model=None, new=None, available=None + self, attrs=None, choices=(), remote=None, model=None, new=None, available=None, + remote_filter=None ): self.remote = remote self.available = available self.model = model self.new = new + self.remote_filter = None + if attrs and "remote_filter" in attrs: + self.remote_filter = attrs.pop("remote_filter") super(Select2Base, self).__init__(attrs, choices) def get_q(self): @@ -275,8 +279,8 @@ class Select2Base(Select2Media): attrs["style"] = "width: 370px" if value and getattr(self, "multiple", False) and \ - not isinstance(value, (list, tuple)): - value = value.split(",") + not isinstance(value, (list, tuple)): + value = value.split(",") options = "" if self.remote: @@ -331,6 +335,8 @@ class Select2Base(Select2Media): html = "<div class='input-group'>" url_new = "new-" + self.model.SLUG url_new = reverse(url_new, args=["id_" + name]) + if self.remote_filter: + url_new += self.remote_filter # WARNING: the modal for the form must be in the main template # "extra_form_modals" list is used for that in form or view new = ( @@ -412,6 +418,8 @@ class Select2BaseField(object): attrs["modal"] = kwargs.pop("modal") if kwargs.get("style", None): attrs["style"] = kwargs.pop("style") + if kwargs.get("remote_filter", None): + attrs["remote_filter"] = kwargs.pop("remote_filter") kwargs["widget"] = widget( model=self.model, available=self.available, |
