Coverage for apis_core/relations/templatetags/relations.py: 47%
55 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-09-30 06:11 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-09-30 06:11 +0000
1from django import template
2from django.apps import apps
3from django.contrib.contenttypes.models import ContentType
4from django.db.models import Case, Q, Value, When
6from apis_core.generic.helpers import first_member_match, module_paths
7from apis_core.relations.models import Relation
8from apis_core.relations.tables import RelationsListTable
9from apis_core.relations.utils import relation_content_types
11register = template.Library()
14@register.simple_tag
15def possible_relation_types_from(obj) -> list[ContentType]:
16 return relation_content_types(any_model=type(obj))
19@register.simple_tag
20def get_relation_targets_from(obj) -> list[ContentType]:
21 relations = relation_content_types(any_model=type(obj))
22 types = set()
23 for model in [relation.model_class() for relation in relations]:
24 if isinstance(obj, model.obj_model_type()):
25 types.add(model.subj_model_type())
26 if isinstance(obj, model.subj_model_type()):
27 types.add(model.obj_model_type())
28 return sorted(
29 list(map(ContentType.objects.get_for_model, types)), key=lambda x: x.name
30 )
33@register.simple_tag
34def relations_from(from_obj, relation_type: ContentType = None):
35 from_content_type = ContentType.objects.get_for_model(from_obj)
36 relation = Relation
37 if relation_type is not None:
38 relation = relation_type.model_class()
40 relations = (
41 relation.objects.filter(
42 Q(subj_content_type=from_content_type, subj_object_id=from_obj.id)
43 | Q(obj_content_type=from_content_type, obj_object_id=from_obj.id)
44 )
45 .annotate(
46 forward=Case(
47 When(
48 subj_content_type=from_content_type,
49 subj_object_id=from_obj.id,
50 then=Value(True),
51 ),
52 default=Value(False),
53 )
54 )
55 .select_subclasses()
56 )
57 return relations
60@register.simple_tag(takes_context=True)
61def relations_list_table(context, relations, suffix=None):
62 suffixes = ["RelationsTable"]
63 if suffix:
64 suffixes.insert(0, f"{suffix}RelationsTable")
65 table_modules = ()
66 for suffix in suffixes:
67 table_modules += module_paths(
68 type(context["object"]), path="tables", suffix=suffix
69 )
70 table_class = first_member_match(table_modules, RelationsListTable)
71 return table_class(relations, request=context["request"])
74@register.simple_tag
75def get_relation_content_types():
76 return relation_content_types()
79@register.simple_tag
80def get_relation_between_content_types(source: ContentType, target: ContentType):
81 return relation_content_types(
82 combination=(source.model_class(), target.model_class())
83 )
86@register.simple_tag(takes_context=True)
87def relations_instances_from_relation_types(context, relation_types):
88 relations = []
89 for relation_type in relation_types:
90 relations.extend(relations_from(context["object"], relation_type))
91 return relations
94@register.simple_tag
95def get_relationmodels() -> list[Relation]:
96 """
97 Return a list of `Relation` models
98 """
99 return list(
100 filter(lambda x: issubclass(x, Relation) and x != Relation, apps.get_models())
101 )