Coverage for apis_core/relations/templatetags/relations.py: 39%

46 statements  

« prev     ^ index     » next       coverage.py v7.6.4, created at 2024-11-22 07:51 +0000

1from django import template 

2from django.contrib.contenttypes.models import ContentType 

3from django.db.models import Case, Q, Value, When 

4 

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 

9 

10register = template.Library() 

11 

12 

13@register.simple_tag 

14def possible_relation_types_from(obj) -> list[ContentType]: 

15 return relation_content_types(any_model=type(obj)) 

16 

17 

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 ) 

30 

31 

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() 

38 

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 

57 

58 

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"]) 

79 

80 

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())