Coverage for apis_core/relations/filtersets.py: 0%
35 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-16 07:42 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-16 07:42 +0000
1from django.db.models import Q
2from django_filters import CharFilter, MultipleChoiceFilter
4from apis_core.apis_metainfo.models import RootObject
5from apis_core.generic.filtersets import GenericFilterSet
6from apis_core.generic.helpers import generate_search_filter
7from apis_core.relations.utils import get_all_relation_subj_and_obj
10class EntityFilter(CharFilter):
11 """
12 Custom CharFilter that uses the generate_search_filter helper
13 to search in all instances inheriting from RootObject and then
14 uses those results to only list relations that point to one of
15 the results.
16 """
18 def __init__(self, *args, **kwargs):
19 super().__init__(*args, **kwargs)
20 self.extra["help_text"] = "Searches in subclasses of RootObject"
22 def _search_all_entities(self, value) -> list[str]:
23 q = Q()
24 for content_type in get_all_relation_subj_and_obj():
25 name = content_type.model
26 q |= Q(**{f"{name}__isnull": False}) & generate_search_filter(
27 content_type.model_class(), value, prefix=f"{name}__"
28 )
29 return RootObject.objects_inheritance.filter(q).values_list("pk", flat=True)
31 def filter(self, qs, value):
32 all_entities = self._search_all_entities(value)
33 return qs.filter(**{f"{self.field_name}_object_id__in": all_entities})
36class SubjObjClassFilter(MultipleChoiceFilter):
37 """
38 Custom MultipleChoiceFilter
39 * it lists model classes as choices, that are in some way
40 connected to a relation, either as subj or as obj
41 * it filters relations by the content types of the connected
42 subjects and objects
43 """
45 def __init__(self, *args, **kwargs):
46 super().__init__(*args, **kwargs)
47 self.extra["choices"] = [
48 (item.id, item.name) for item in get_all_relation_subj_and_obj()
49 ]
51 def filter(self, qs, value: list[str] | None):
52 # value is the list of contenttypes ids
53 if value:
54 return qs.filter(Q(**{f"{self.field_name}_content_type__in": value}))
55 return qs
58class RelationFilterSet(GenericFilterSet):
59 """
60 Override the GenericFilterSet that is created for the Relation model.
61 It does not really make sense to filter for content type id and object id,
62 so we exclude those.
63 Instead, we add a multiple choice filter for object and subject class, that
64 only lists those choices that actually exists (meaning the classes that are
65 actually set as subj or obj in some relation).
66 Additionaly, we add a search filter, that searches in instances connected
67 to relations (this does only work for instances inheriting from RootObject).
68 """
70 subj_search = EntityFilter(
71 field_name="subj",
72 label="Subject search",
73 )
74 obj_search = EntityFilter(
75 field_name="obj",
76 label="Object search",
77 )
78 subj_class = SubjObjClassFilter(
79 field_name="subj",
80 label="Subject class",
81 )
82 obj_class = SubjObjClassFilter(
83 field_name="obj",
84 label="Object class",
85 )
87 class Meta:
88 exclude = [
89 "subj_object_id",
90 "subj_content_type",
91 "obj_object_id",
92 "obj_content_type",
93 ]
94 form = GenericFilterSet.Meta.form