Coverage for apis_core/relations/utils.py: 26%
35 statements
« prev ^ index » next coverage.py v7.6.8, created at 2024-12-20 09:24 +0000
« prev ^ index » next coverage.py v7.6.8, created at 2024-12-20 09:24 +0000
1import functools
3from django.contrib.contenttypes.models import ContentType
5from apis_core.relations.models import Relation
8def is_relation(ct: ContentType) -> bool:
9 mc = ct.model_class()
10 return (
11 issubclass(mc, Relation)
12 and hasattr(mc, "subj_model")
13 and hasattr(mc, "obj_model")
14 )
17@functools.cache
18def relation_content_types(
19 subj_model=None, obj_model=None, any_model=None, combination=(None, None)
20) -> set[ContentType]:
21 allcts = list(
22 filter(
23 lambda contenttype: contenttype.model_class() is not None,
24 ContentType.objects.all(),
25 )
26 )
27 relationcts = list(filter(lambda contenttype: is_relation(contenttype), allcts))
28 if subj_model is not None:
29 relationcts = list(
30 filter(
31 lambda contenttype: subj_model in contenttype.model_class().subj_list(),
32 relationcts,
33 )
34 )
35 if obj_model is not None:
36 relationcts = list(
37 filter(
38 lambda contenttype: obj_model in contenttype.model_class().obj_list(),
39 relationcts,
40 )
41 )
42 if any_model is not None:
43 relationcts = list(
44 filter(
45 lambda contenttype: any_model in contenttype.model_class().obj_list()
46 or any_model in contenttype.model_class().subj_list(),
47 relationcts,
48 )
49 )
50 if all(combination):
51 left, right = combination
52 rels = list(
53 filter(
54 lambda contenttype: right in contenttype.model_class().obj_list()
55 and left in contenttype.model_class().subj_list(),
56 relationcts,
57 )
58 )
59 rels.extend(
60 list(
61 filter(
62 lambda contenttype: left in contenttype.model_class().obj_list()
63 and right in contenttype.model_class().subj_list(),
64 relationcts,
65 )
66 )
67 )
68 relationcts = rels
69 return set(relationcts)
72def relation_match_target(relation, target: ContentType) -> bool:
73 """
74 test if a relation points to a target
75 this function should not be cached, because the `forward` attribute
76 is an annotation that does not seem to be part of the relation, so
77 if cached, method could be called with another `forward` value and
78 return the wrong result
79 """
80 if relation.forward and relation.obj_content_type == target:
81 return True
82 if not relation.forward and relation.subj_content_type == target:
83 return True
84 return False
87@functools.cache
88def get_all_relation_subj_and_obj() -> list[ContentType]:
89 """
90 Return the model classes of any model that is in some way
91 connected to a relation - either as obj or as subj
93 Returns:
94 list[ContentType]: A list of unique ContentTypes for related models.
95 """
96 related_models = set()
97 for rel in relation_content_types():
98 related_models.update(rel.model_class().subj_list())
99 related_models.update(rel.model_class().obj_list())
100 return [ContentType.objects.get_for_model(item) for item in related_models]