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
« 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
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
11register = template.Library()
14@register.filter
15def contenttype(model):
16 return ContentType.objects.get_for_model(model)
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
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()
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)
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
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
98@register.filter
99def get_attribute(obj, attribute):
100 return getattr(obj, attribute, None)
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()
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 )
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 )
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
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
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))
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"]