Coverage for apis_core/relations/templatetags/relations.py: 39%
46 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
1from django import template
2from django.contrib.contenttypes.models import ContentType
3from django.db.models import Case, Q, Value, When
5from apis_core.generic.helpers import first_member_match, module_paths, mro_paths
6from apis_core.relations.models import Relation
7from apis_core.relations.tables import RelationsListTable
8from apis_core.relations.utils import relation_content_types, relation_match_target
10register = template.Library()
13@register.simple_tag
14def possible_relation_types_from(obj) -> list[ContentType]:
15 return relation_content_types(any_model=type(obj))
18@register.simple_tag
19def get_relation_targets_from(obj) -> list[ContentType]:
20 relations = relation_content_types(any_model=type(obj))
21 types = set()
22 for model in [relation.model_class() for relation in relations]:
23 if type(obj) in model.obj_list():
24 types.update(model.subj_list())
25 if type(obj) in model.subj_list():
26 types.update(model.obj_list())
27 return sorted(
28 list(map(ContentType.objects.get_for_model, types)), key=lambda x: x.name
29 )
32@register.simple_tag
33def relations_from(from_obj, relation_type: ContentType = None):
34 from_content_type = ContentType.objects.get_for_model(from_obj)
35 relation = Relation
36 if relation_type is not None:
37 relation = relation_type.model_class()
39 relations = (
40 relation.objects.filter(
41 Q(subj_content_type=from_content_type, subj_object_id=from_obj.id)
42 | Q(obj_content_type=from_content_type, obj_object_id=from_obj.id)
43 )
44 .annotate(
45 forward=Case(
46 When(
47 subj_content_type=from_content_type,
48 subj_object_id=from_obj.id,
49 then=Value(True),
50 ),
51 default=Value(False),
52 )
53 )
54 .select_subclasses()
55 )
56 return relations
59@register.simple_tag(takes_context=True)
60def relations_list_table(context, relations, target=None):
61 suffixes = ["RelationsTable"]
62 if target:
63 suffixes.extend(
64 f"{module[-1]}RelationsTable" for module in mro_paths(target.model_class())
65 )
66 table_modules = ()
67 for suffix in suffixes:
68 table_modules += module_paths(
69 type(context["object"]), path="tables", suffix=suffix
70 )
71 table_class = first_member_match(table_modules, RelationsListTable)
72 if target:
73 relations = [
74 relation
75 for relation in relations
76 if relation_match_target(relation, target)
77 ]
78 return table_class(relations, request=context["request"])
81@register.simple_tag
82def relations_verbose_name_listview_url():
83 """
84 Return all relations verbose names together with their list uri, sorted in alphabetical order
85 USED BY:
86 * `apis_core/relations/templates/base.html` (to extend the default `base.html`)
87 """
88 relation_classes = [relation.model_class() for relation in relation_content_types()]
89 ret = {
90 relation._meta.verbose_name: relation.get_listview_url()
91 for relation in relation_classes
92 }
93 return sorted(ret.items())