Coverage for apis_core/generic/templatetags/generic.py: 36%
99 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-06-25 10:00 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-06-25 10:00 +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):
21 data = {}
22 for f in get_model_fields(instance):
23 if not getattr(f, "editable", False):
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, suffix):
113 return template_names_via_mro(type(obj), suffix)
116@register.simple_tag(takes_context=True)
117def any_view_permission(context, content_types):
118 user = context.request.user
119 return any(
120 [user.has_perm(ct.model_class().get_view_permission()) for ct in content_types]
121 )
124@register.simple_tag
125def content_types_by_natural_keys(natural_keys: tuple() = ()) -> [ContentType]:
126 """
127 Convert a list of natural keys to a list of ContentType models
128 If any of the natural keys does not refer to an existing model, raise a 404
129 """
130 content_types = []
131 for key in natural_keys:
132 app_label, model = key.split(".")
133 content_type = get_object_or_404(ContentType, app_label=app_label, model=model)
134 content_types.append(content_type)
135 return content_types
138@register.simple_tag
139def natural_keys_by_content_types(content_types: tuple() = ()) -> [str]:
140 """
141 Convert a list of ContentType models to their natural key
142 """
143 natural_keys = []
144 for content_type in content_types:
145 natural_keys.append(content_type.app_label + "." + content_type.model)
146 return natural_keys
149@register.filter
150def split(string: str = "", delimiter=",") -> [str]:
151 """
152 Split a string by a specific delimiter and also strip the string of
153 leading and trailing whitespaces.
154 """
155 return map(str.strip, string.split(delimiter))
158@register.simple_tag
159def model_field_template_lookup_list(model, field, suffix="") -> [str]:
160 """
161 generate a template path based on the modelname, the fieldname and
162 the suffix. return a list with this template path and a fallback
163 path.
164 """
165 content_type = ContentType.objects.get_for_model(model)
166 path = f"{content_type.app_label}/partials/{content_type.model}_{field.name}_{suffix}.html"
167 return [path, f"generic/partials/default_model_field_{suffix}.html"]