From a362c5580e76d938e593a770a54b253b1c03c016 Mon Sep 17 00:00:00 2001 From: Horilla Date: Thu, 5 Jun 2025 16:59:52 +0530 Subject: [PATCH] [UPDT] HORILLA_VIEWS: Converted string entries in group_by_fields to (field, verbose_name) tuples --- horilla_views/generic/cbv/views.py | 49 +++++++++++++++++++ .../templatetags/generic_template_filters.py | 35 +++++++------ 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/horilla_views/generic/cbv/views.py b/horilla_views/generic/cbv/views.py index d6352992b..927f32f1b 100644 --- a/horilla_views/generic/cbv/views.py +++ b/horilla_views/generic/cbv/views.py @@ -12,6 +12,7 @@ from bs4 import BeautifulSoup from django import forms from django.contrib import messages from django.core.cache import cache as CACHE +from django.core.exceptions import FieldDoesNotExist from django.core.paginator import Page from django.http import HttpRequest, HttpResponse, QueryDict from django.shortcuts import render @@ -1263,10 +1264,58 @@ class HorillaNavView(TemplateView): def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) + self._initialize_model_and_group_fields() request = getattr(_thread_locals, "request", None) self.request = request # update_initial_cache(request, CACHE, HorillaNavView) + def _initialize_model_and_group_fields(self) -> None: + """ + Initialize model_class and reinitialize filter_instance if model exists + for updating group_by_fields with verbose names. + """ + if not self.filter_instance: + return + + model_class_ref = self.filter_instance._meta.model + if not model_class_ref: + return + + model_instance = model_class_ref() + self.nav_title = self.nav_title or model_instance._meta.verbose_name_plural + self.filter_instance = self.filter_instance.__class__() + + if not self.group_by_fields: + return + + get_field = model_instance._meta.get_field + updated_fields = [] + append = updated_fields.append + + for field in self.group_by_fields: + if isinstance(field, str): + try: + verbose_name = get_field(field).verbose_name + append((field, verbose_name)) + except FieldDoesNotExist: + # Check for related fields (field paths with '__') + if "__" in field and hasattr( + model_class_ref, "get_verbose_name_related_field" + ): + try: + verbose_name = ( + model_class_ref.get_verbose_name_related_field(field) + ) + append((field, verbose_name)) + continue + except Exception as e: + pass + append(field) + else: + append(field) + + self.group_by_fields = updated_fields + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["nav_title"] = self.nav_title diff --git a/horilla_views/templatetags/generic_template_filters.py b/horilla_views/templatetags/generic_template_filters.py index 7f1966dbc..b31bc0151 100644 --- a/horilla_views/templatetags/generic_template_filters.py +++ b/horilla_views/templatetags/generic_template_filters.py @@ -22,7 +22,7 @@ from horilla.horilla_middlewares import _thread_locals register = template.Library() -numeric_test = re.compile(r'^\d+$') +numeric_test = re.compile(r"^\d+$") date_format_mapping = { "DD-MM-YYYY": "%d-%m-%Y", @@ -87,28 +87,31 @@ def getattribute(value, attr: str): @register.filter(name="format") def format(string: str, instance: object): """ - format + Format a string by resolving instance attributes, including method calls like get_status_display. """ attr_placeholder_regex = r"{([^}]*)}" attr_placeholders = re.findall(attr_placeholder_regex, string) if not attr_placeholders: return string - flag = instance - format_context = {} - for attr_placeholder in attr_placeholders: - attr_name: str = attr_placeholder - attrs = attr_name.split("__") - for attr in attrs: - value = getattr(instance, attr, "") - if isinstance(value, types.MethodType): - value = value() - instance = value - format_context[attr_name] = value - instance = flag - formatted_string = string.format(**format_context) - return formatted_string + original_instance = instance + format_context = {} + + for attr_placeholder in attr_placeholders: + instance = original_instance # reset each time + attrs = attr_placeholder.split("__") + try: + for attr in attrs: + instance = getattr(instance, attr, "") + # If final resolved attr is a method, call it + if callable(instance): + instance = instance() + except Exception: + instance = "" + format_context[attr_placeholder] = instance + + return string.format(**format_context) @register.filter("accessibility")