From 4c02e3cda364a8455872a9ec9b3417c10a5c66b7 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Wed, 28 Feb 2018 06:55:52 -0500 Subject: [PATCH] Refs #27728 -- Made cosmetic edits to admin template tag template overriding. --- .../contrib/admin/templatetags/admin_list.py | 10 +---- .../admin/templatetags/admin_modify.py | 10 +---- django/contrib/admin/templatetags/base.py | 15 ++++---- docs/ref/contrib/admin/index.txt | 4 +- docs/releases/2.1.txt | 15 +++++--- tests/admin_views/test_templatetags.py | 37 ++++++++++--------- 6 files changed, 43 insertions(+), 48 deletions(-) diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index ff04faed940..22dec6994fc 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -475,17 +475,11 @@ def admin_actions_tag(parser, token): return InclusionAdminNode(parser, token, func=admin_actions, template_name='actions.html') -def change_list_object_tools(context): - """ - Displays the row of change list object tools. - """ - return context - - @register.tag(name='change_list_object_tools') def change_list_object_tools_tag(parser, token): + """Display the row of change list object tools.""" return InclusionAdminNode( parser, token, - func=change_list_object_tools, + func=lambda context: context, template_name='change_list_object_tools.html', ) diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py index 95f0fc977cf..82bb6c9be2e 100644 --- a/django/contrib/admin/templatetags/admin_modify.py +++ b/django/contrib/admin/templatetags/admin_modify.py @@ -76,18 +76,12 @@ def submit_row_tag(parser, token): return InclusionAdminNode(parser, token, func=submit_row, template_name='submit_line.html') -def change_form_object_tools(context): - """ - Displays the row of change form object tools. - """ - return context - - @register.tag(name='change_form_object_tools') def change_form_object_tools_tag(parser, token): + """Display the row of change form object tools.""" return InclusionAdminNode( parser, token, - func=change_form_object_tools, + func=lambda context: context, template_name='change_form_object_tools.html', ) diff --git a/django/contrib/admin/templatetags/base.py b/django/contrib/admin/templatetags/base.py index a26a84d0de8..2d261c0e884 100644 --- a/django/contrib/admin/templatetags/base.py +++ b/django/contrib/admin/templatetags/base.py @@ -4,19 +4,20 @@ from django.template.library import InclusionNode, parse_bits class InclusionAdminNode(InclusionNode): + """ + Template tag that allows its template to be overridden per model, per app, + or globally. + """ + def __init__(self, parser, token, func, template_name, takes_context=True): self.template_name = template_name - params, varargs, varkw, defaults, kwonly, kwonly_defaults, _ = getfullargspec(func) - if len(params) > 0 and params[0] == 'self': - params = params[1:] # ignore 'self' bits = token.split_contents() args, kwargs = parse_bits( - parser, bits[1:], params, varargs, varkw, defaults, kwonly, kwonly_defaults, takes_context, bits[0] - ) - super().__init__( - func=func, takes_context=takes_context, args=args, kwargs=kwargs, filename=None + parser, bits[1:], params, varargs, varkw, defaults, kwonly, + kwonly_defaults, takes_context, bits[0], ) + super().__init__(func, takes_context, args, kwargs, filename=None) def render(self, context): opts = context['opts'] diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 5ea78d22789..face1297ace 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -2674,6 +2674,8 @@ And that's it! If we placed this file in the ``templates/admin/my_app`` directory, our link would appear on the change form for all models within my_app. +.. _admin-templates-overridden-per-app-or-model: + Templates which may be overridden per app or model -------------------------------------------------- @@ -2701,7 +2703,7 @@ app or per model. The following can: The ability to override the ``actions.html``, ``change_form_object_tools.html``, ``change_list_object_tools.html``, ``change_list_results.html``, ``date_hierarchy.html``, ``pagination.html``, ``prepopulated_fields_js.html``, - ``search_form.html``, ``submit_line.html`` templates were added. + ``search_form.html``, and ``submit_line.html`` templates was added. For those templates that cannot be overridden in this way, you may still override them for your entire project. Just place the new version in your diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt index d6cb44caa14..3495a132a60 100644 --- a/docs/releases/2.1.txt +++ b/docs/releases/2.1.txt @@ -52,13 +52,16 @@ Minor features * The new :meth:`.ModelAdmin.get_deleted_objects()` method allows customizing the deletion process of the delete view and the "delete selected" action. -* The ``actions.html``, ``change_list_results.html``, ``date_hierarchy.html``, - ``pagination.html``, ``prepopulated_fields_js.html``, ``search_form.html`` - and ``submit_line.html`` templates can be overridden even per app or - per model, other than globally. -* The admin change list and change form object tools can now be overridden per app, - per model or globally with ``change_list_object_tools.html`` and +* The ``actions.html``, ``change_list_results.html``, ``date_hierarchy.html``, + ``pagination.html``, ``prepopulated_fields_js.html``, ``search_form.html``, + and ``submit_line.html`` templates can now be :ref:`overridden per app or + per model ` (besides overridden + globally). + +* The admin change list and change form object tools can now be :ref:`overridden + per app, per model, or globally ` + with ``change_list_object_tools.html`` and ``change_form_object_tools.html`` templates. :mod:`django.contrib.admindocs` diff --git a/tests/admin_views/test_templatetags.py b/tests/admin_views/test_templatetags.py index db78636d5d7..4f33bbd7244 100644 --- a/tests/admin_views/test_templatetags.py +++ b/tests/admin_views/test_templatetags.py @@ -7,7 +7,6 @@ from django.contrib.auth.admin import UserAdmin from django.contrib.auth.models import User from django.test import RequestFactory, TestCase from django.urls import reverse -from django.utils.encoding import force_text from .admin import ArticleAdmin, site from .models import Article, Question @@ -29,9 +28,10 @@ class AdminTemplateTagsTest(AdminViewBasicTestCase): self.assertIs(template_context['extra'], True) self.assertIs(template_context['show_save'], True) - def test_can_override_change_form_templatetags(self): + def test_override_change_form_template_tags(self): """ - admin_modify templatetags can follow the 'standard' search patter admin/app_label/model/template.html + admin_modify template tags follow the standard search pattern + admin/app_label/model/template.html. """ factory = RequestFactory() article = Article.objects.all()[0] @@ -43,31 +43,32 @@ class AdminTemplateTagsTest(AdminViewBasicTestCase): response.render() self.assertIs(response.context_data['show_publish'], True) self.assertIs(response.context_data['extra'], True) - content = force_text(response.content) - self.assertIs('name="_save"' in content, True) - self.assertIs('name="_publish"' in content, True) - self.assertIs('override-change_form_object_tools' in content, True) - self.assertIs('override-prepopulated_fields_js' in content, True) + content = str(response.content) + self.assertIn('name="_save"', content) + self.assertIn('name="_publish"', content) + self.assertIn('override-change_form_object_tools', content) + self.assertIn('override-prepopulated_fields_js', content) - def test_can_override_change_list_templatetags(self): + def test_override_change_list_template_tags(self): """ - admin_list templatetags can follow the 'standard' search patter admin/app_label/model/template.html + admin_list template tags follow the standard search pattern + admin/app_label/model/template.html. """ factory = RequestFactory() request = factory.get(reverse('admin:admin_views_article_changelist')) request.user = self.superuser admin = ArticleAdmin(Article, site) admin.date_hierarchy = 'date' - admin.search_fields = ('title', 'content',) + admin.search_fields = ('title', 'content') response = admin.changelist_view(request) response.render() - content = force_text(response.content) - self.assertIs('override-actions' in content, True) - self.assertIs('override-change_list_object_tools' in content, True) - self.assertIs('override-change_list_results' in content, True) - self.assertIs('override-date_hierarchy' in content, True) - self.assertIs('override-pagination' in content, True) - self.assertIs('override-search_form' in content, True) + content = str(response.content) + self.assertIn('override-actions', content) + self.assertIn('override-change_list_object_tools', content) + self.assertIn('override-change_list_results', content) + self.assertIn('override-date_hierarchy', content) + self.assertIn('override-pagination', content) + self.assertIn('override-search_form', content) class DateHierarchyTests(TestCase):