From 4ebe555ff19801d02231b574a12e422c59a66c0d Mon Sep 17 00:00:00 2001 From: Birger Schacht Date: Thu, 13 Jun 2024 12:25:16 +0200 Subject: [PATCH] fix(apis_entities): only list possible properties in filterset form The filter `related_properties` listed all the existing properties, but it makes more sense to only list the properties that can have the model the filter filters as a `subj` or an `obj`. Closes: #949 --- apis_core/apis_entities/filtersets.py | 42 +++++++++++++++++++++------ 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/apis_core/apis_entities/filtersets.py b/apis_core/apis_entities/filtersets.py index 570d99c86..daa876d25 100644 --- a/apis_core/apis_entities/filtersets.py +++ b/apis_core/apis_entities/filtersets.py @@ -1,8 +1,10 @@ import django_filters from django.db import models +from django.db.models import Q from apis_core.generic.filtersets import GenericFilterSet, GenericFilterSetForm from apis_core.apis_relations.models import Property from apis_core.generic.helpers import generate_search_filter +from django.contrib.contenttypes.models import ContentType ABSTRACT_ENTITY_FILTERS_EXCLUDE = [ "rootobject_ptr", @@ -22,10 +24,31 @@ ] -def related_property(queryset, name, value): - p = Property.objects.get(name_forward=value) - queryset = queryset.filter(triple_set_from_subj__prop=p).distinct() - return queryset +class PropertyFilter(django_filters.ModelChoiceFilter): + """ + A child of ModelChoiceFilter that only works with + Properties, but in return it filters those so that + only the Properties are listed that can be connected + to the `model` given as argument. + """ + + def __init__(self, *args, **kwargs): + model = kwargs.pop("model", None) + super().__init__(*args, **kwargs) + + if model is not None: + ct = ContentType.objects.get_for_model(model) + self.queryset = ( + Property.objects.all() + .order_by("name_forward") + .filter(Q(subj_class=ct) | Q(obj_class=ct)) + .distinct() + ) + + def filter(queryset, name, value): + p = Property.objects.get(name_forward=value) + queryset = queryset.filter(triple_set_from_subj__prop=p).distinct() + return queryset def related_entity(queryset, name, value): @@ -41,11 +64,6 @@ class AbstractEntityFilterSet(GenericFilterSet): related_entity = django_filters.CharFilter( method=related_entity, label="Related entity contains" ) - related_property = django_filters.ModelChoiceFilter( - queryset=Property.objects.all().order_by("name_forward"), - label="Related Property", - method=related_property, - ) class Meta(GenericFilterSet.Meta): form = AbstractEntityFilterSetForm @@ -58,3 +76,9 @@ class Meta(GenericFilterSet.Meta): }, }, } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.filters["related_property"] = PropertyFilter( + label="Related Property", model=getattr(self.Meta, "model", None) + )