From 0c005a22b41d05a99bf0f4ecd363a33aedb8a232 Mon Sep 17 00:00:00 2001 From: Cuong Nguyen Date: Fri, 24 Feb 2023 17:25:12 +0700 Subject: [PATCH] add custom object-tools --- admin_extended/base.py | 4 +- admin_extended/decorators.py | 11 +++ admin_extended/mixins.py | 90 ++++++++++++++++++- .../templates/admin/change_list.html | 8 ++ .../admin/custom/custom_object_tools.html | 2 +- 5 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 admin_extended/decorators.py create mode 100644 admin_extended/templates/admin/change_list.html diff --git a/admin_extended/base.py b/admin_extended/base.py index e42bcce..7dbb52b 100644 --- a/admin_extended/base.py +++ b/admin_extended/base.py @@ -4,7 +4,7 @@ from django.contrib import admin from django.shortcuts import render from django.urls import path -from .mixins import UIUtilsMixin, ChangeFormActionAdminModelMixin +from .mixins import UIUtilsMixin, ChangeFormActionAdminModelMixin, ObjectToolModelAdminMixin from .settings import ADMIN_EXTENDED_SETTINGS @@ -13,7 +13,7 @@ def has_search_fields(field): return model_admin and model_admin.search_fields -class ExtendedAdminModel(ChangeFormActionAdminModelMixin, UIUtilsMixin, admin.ModelAdmin): +class ExtendedAdminModel(ObjectToolModelAdminMixin, UIUtilsMixin, admin.ModelAdmin): """ Extend base model admin: tabbable inline model, separate view, edit model,... diff --git a/admin_extended/decorators.py b/admin_extended/decorators.py new file mode 100644 index 0000000..b0f0b18 --- /dev/null +++ b/admin_extended/decorators.py @@ -0,0 +1,11 @@ +def object_tool(function=None, *, icon=None, name=None, description=None): + def decorator(func): + func.icon = icon + func.name = name + func.description = description + + return func + + if function is None: + return decorator + return decorator(function) diff --git a/admin_extended/mixins.py b/admin_extended/mixins.py index 14f8e44..3cf10d8 100644 --- a/admin_extended/mixins.py +++ b/admin_extended/mixins.py @@ -48,7 +48,7 @@ def get_urls(self): def get_change_form_actions(self, request, object_id): return [x() for x in self.change_form_action_classes] - def get_change_form_object_tools(self, request, object_id): + def get_change_form_object_tools1(self, request, object_id): return self.change_form_object_tools def change_from_action_view(self, request): @@ -74,7 +74,93 @@ def _changeform_view(self, request, object_id, form_url, extra_context): extra_context['change_form_actions'] = change_form_actions extra_context['change_form_action_url'] = reverse(action_url_name) - change_form_object_tools = self.get_change_form_object_tools(request, object_id) + change_form_object_tools = self.get_change_form_object_tools1(request, object_id) extra_context['change_form_object_tools'] = change_form_object_tools return super()._changeform_view(request, object_id, form_url, extra_context) + +class ObjectToolModelAdminMixin: + change_form_object_tools = [] + change_list_object_tools = [] + + def get_urls(self): + urls = super().get_urls() + + base_url_name = "%s_%s" % (self.model._meta.app_label, self.model._meta.model_name) + custom_urls = [ + path( + '/object-tools/', + self.admin_site.admin_view(self.change_form_object_tool_view), + name=f'{base_url_name}_change_form_object_tool' + ), + path( + 'object-tools/', + self.admin_site.admin_view(self.change_list_object_tool_view), + name=f'{base_url_name}_change_list_object_tool' + ), + ] + return custom_urls + urls + + def get_change_form_object_tools(self, request): + object_tools = [] + for change_form_object_tool in self.change_form_object_tools: + object_tool = getattr(self, change_form_object_tool) + object_tools.append(object_tool) + return {object_tool.name: object_tool for object_tool in object_tools} + + + def change_form_object_tool_view(self, request, object_id, name): + change_form_object_tools = self.get_change_form_object_tools(request) + return change_form_object_tools[name](request, object_id) + + + def _get_render_change_form_object_tools(self, request, object_id): + base_url_name = "%s_%s" % (self.model._meta.app_label, self.model._meta.model_name) + change_form_object_tools = self.get_change_form_object_tools(request) + result = [] + for name, object_tool in change_form_object_tools.items(): + result.append({ + 'icon': object_tool.icon, + 'url': reverse(f'admin:{base_url_name}_change_form_object_tool', args=[object_id, name]), + 'description': object_tool.description, + }) + return result + + + def changeform_view(self, request, object_id=None, form_url="", extra_context=None): + if object_id: + extra_context = extra_context if extra_context else {} + extra_context['change_form_object_tools'] = self._get_render_change_form_object_tools(request, object_id) + + return super().changeform_view(request, object_id, form_url, extra_context) + + + def get_change_list_object_tools(self, request): + object_tools = [] + for change_list_object_tool in self.change_list_object_tools: + object_tool = getattr(self, change_list_object_tool) + object_tools.append(object_tool) + return {object_tool.name: object_tool for object_tool in object_tools} + + + def change_list_object_tool_view(self, request, name): + change_list_object_tools = self.get_change_list_object_tools(request) + return change_list_object_tools[name](request) + + def _get_render_change_list_object_tools(self, request): + base_url_name = "%s_%s" % (self.model._meta.app_label, self.model._meta.model_name) + change_list_object_tools = self.get_change_list_object_tools(request) + result = [] + for name, object_tool in change_list_object_tools.items(): + result.append({ + 'icon': object_tool.icon, + 'url': reverse(f'admin:{base_url_name}_change_list_object_tool', args=[name]), + 'description': object_tool.description, + }) + return result + + def changelist_view(self, request, extra_context=None): + extra_context = extra_context if extra_context else {} + extra_context['change_list_object_tools'] = self._get_render_change_list_object_tools(request) + + return super().changelist_view(request, extra_context) \ No newline at end of file diff --git a/admin_extended/templates/admin/change_list.html b/admin_extended/templates/admin/change_list.html new file mode 100644 index 0000000..ff637a3 --- /dev/null +++ b/admin_extended/templates/admin/change_list.html @@ -0,0 +1,8 @@ +{% extends "admin/change_list.html" %} + +{% block object-tools-items %} + {% for item in change_list_object_tools %} +
  • {{ item.description }}
  • + {% endfor %} + {{ block.super }} +{% endblock %} \ No newline at end of file diff --git a/admin_extended/templates/admin/custom/custom_object_tools.html b/admin_extended/templates/admin/custom/custom_object_tools.html index 540dd8d..34841ff 100644 --- a/admin_extended/templates/admin/custom/custom_object_tools.html +++ b/admin_extended/templates/admin/custom/custom_object_tools.html @@ -1,3 +1,3 @@ {% for item in change_form_object_tools %} -
  • {{ item.title }}
  • +
  • {{ item.description }}
  • {% endfor %}