Coverage for apis_core/generic/templatetags/generic.py: 77%

99 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-10-30 12:03 +0000

1from django import template 

2from django.apps import apps 

3from django.contrib.contenttypes.models import ContentType 

4from django.core.exceptions import ObjectDoesNotExist 

5from django.shortcuts import get_object_or_404 

6 

7from apis_core.core.templatetags.core import get_model_fields 

8from apis_core.generic.abc import GenericModel 

9from apis_core.generic.helpers import template_names_via_mro 

10 

11register = template.Library() 

12 

13 

14@register.filter 

15def contenttype(model): 

16 return ContentType.objects.get_for_model(model) 

17 

18 

19@register.simple_tag 

20def modeldict(instance, fields=None, exclude=None, exclude_noneditable=True): 

21 data = {} 

22 for f in get_model_fields(instance): 

23 if not getattr(f, "editable", False) and exclude_noneditable: 

24 continue 

25 if fields is not None and f.name not in fields: 

26 continue 

27 if exclude and f.name in exclude: 

28 continue 

29 field = instance._meta.get_field(f.name) 

30 try: 

31 data[field] = getattr(instance, field.name) 

32 except ObjectDoesNotExist as e: 

33 data[field] = f"{field.value_from_object(instance)} ({e})" 

34 if fn := getattr(instance, f"get_{field.name}_display", False): 

35 data[field] = fn() 

36 if getattr(field, "m2m_field_name", False): 

37 values = getattr(instance, field.name).all() 

38 data[field] = ", ".join([str(value) for value in values]) 

39 return data 

40 

41 

42@register.simple_tag 

43def contenttypes(app_labels=None): 

44 if app_labels: 

45 app_labels = app_labels.split(",") 

46 return ContentType.objects.filter(app_label__in=app_labels) 

47 return ContentType.objects.all() 

48 

49 

50def is_genericmodel(content_type: ContentType): 

51 model_class = content_type.model_class() 

52 return model_class is not None and issubclass(model_class, GenericModel) 

53 

54 

55@register.simple_tag 

56def genericmodel_content_types(): 

57 """ 

58 Retrieve all models which inherit from GenericModel class 

59 and return their ContentType. 

60 """ 

61 genericmodels = list( 

62 filter( 

63 lambda content_type: is_genericmodel(content_type), 

64 ContentType.objects.all(), 

65 ) 

66 ) 

67 return genericmodels 

68 

69 

70@register.simple_tag 

71def pure_genericmodel_content_types(): 

72 """ 

73 Retrieve all models which inherit from GenericModel class 

74 but are not Collections, Entities, Relations or History models 

75 """ 

76 parents = [] 

77 if apps.is_installed("apis_core.collections"): 

78 collections = apps.get_app_config("collections") 

79 parents.append(collections.models_module.SkosCollection) 

80 parents.append(collections.models_module.SkosCollectionContentObject) 

81 if apps.is_installed("apis_core.relations"): 

82 relations = apps.get_app_config("relations") 

83 parents.append(relations.models_module.Relation) 

84 if apps.is_installed("apis_core.history"): 

85 history = apps.get_app_config("history") 

86 parents.append(history.models_module.APISHistoryTableBase) 

87 if apps.is_installed("apis_core.apis_entities"): 

88 entities = apps.get_app_config("apis_entities") 

89 parents.append(entities.models_module.AbstractEntity) 

90 genericmodels = [ 

91 ct 

92 for ct in set(genericmodel_content_types()) 

93 if not issubclass(ct.model_class(), tuple(parents)) 

94 ] 

95 return genericmodels 

96 

97 

98@register.filter 

99def get_attribute(obj, attribute): 

100 return getattr(obj, attribute, None) 

101 

102 

103@register.filter 

104def content_type_count(content_type): 

105 """ 

106 Return the number of objects having a specific content type 

107 """ 

108 return content_type.model_class().objects.count() 

109 

110 

111@register.simple_tag 

112def template_list(obj, folder="", prefix="", suffix=""): 

113 return template_names_via_mro( 

114 type(obj), folder=folder, prefix=prefix, suffix=suffix 

115 ) 

116 

117 

118@register.simple_tag(takes_context=True) 

119def any_view_permission(context, content_types): 

120 user = context.request.user 

121 return any( 

122 [user.has_perm(ct.model_class().get_view_permission()) for ct in content_types] 

123 ) 

124 

125 

126@register.simple_tag 

127def content_types_by_natural_keys(natural_keys: tuple() = ()) -> [ContentType]: 

128 """ 

129 Convert a list of natural keys to a list of ContentType models 

130 If any of the natural keys does not refer to an existing model, raise a 404 

131 """ 

132 content_types = [] 

133 for key in natural_keys: 

134 app_label, model = key.split(".") 

135 content_type = get_object_or_404(ContentType, app_label=app_label, model=model) 

136 content_types.append(content_type) 

137 return content_types 

138 

139 

140@register.simple_tag 

141def natural_keys_by_content_types(content_types: tuple() = ()) -> [str]: 

142 """ 

143 Convert a list of ContentType models to their natural key 

144 """ 

145 natural_keys = [] 

146 for content_type in content_types: 

147 natural_keys.append(content_type.app_label + "." + content_type.model) 

148 return natural_keys 

149 

150 

151@register.filter 

152def split(string: str = "", delimiter=",") -> [str]: 

153 """ 

154 Split a string by a specific delimiter and also strip the string of 

155 leading and trailing whitespaces. 

156 """ 

157 return map(str.strip, string.split(delimiter)) 

158 

159 

160@register.simple_tag 

161def model_field_template_lookup_list(model, field, suffix="") -> [str]: 

162 """ 

163 generate a template path based on the modelname, the fieldname and 

164 the suffix. return a list with this template path and a fallback 

165 path. 

166 """ 

167 content_type = ContentType.objects.get_for_model(model) 

168 path = f"{content_type.app_label}/partials/{content_type.model}_{field.name}_{suffix}.html" 

169 return [path, f"generic/partials/default_model_field_{suffix}.html"]