Coverage for apis_core/relations/utils.py: 28%

36 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-16 07:42 +0000

1import functools 

2 

3from django.contrib.contenttypes.models import ContentType 

4 

5from apis_core.relations.models import Relation 

6 

7 

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 ) 

15 

16 

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) 

70 

71 

72@functools.cache 

73def relation_match_target(relation, target: ContentType) -> bool: 

74 if relation.forward and relation.obj_content_type == target: 

75 return True 

76 if not relation.forward and relation.subj_content_type == target: 

77 return True 

78 return False 

79 

80 

81@functools.cache 

82def get_all_relation_subj_and_obj() -> list[ContentType]: 

83 """ 

84 Return the model classes of any model that is in some way 

85 connected to a relation - either as obj or as subj 

86 

87 Returns: 

88 list[ContentType]: A list of unique ContentTypes for related models. 

89 """ 

90 related_models = set() 

91 for rel in relation_content_types(): 

92 related_models.update(rel.model_class().subj_list()) 

93 related_models.update(rel.model_class().obj_list()) 

94 return [ContentType.objects.get_for_model(item) for item in related_models]