From a962286b74f1e8c8cb19fb45a057800da8c2fb56 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Fri, 6 Sep 2013 12:31:44 -0500 Subject: [PATCH] Added AdminSite attributes for easily changing admin title. AdminSite now has overridable site_header, site_title and index_title attributes. Changed each admin view to pass these to the context (in a new AdminSite.each_context() method). The intent here is to make it easier to override these things in the common case, instead of having to override a template, which is a bigger burden. --- django/contrib/admin/options.py | 118 +++++++++--------- django/contrib/admin/sites.py | 55 +++++--- .../admin/templates/admin/base_site.html | 5 +- docs/ref/contrib/admin/index.txt | 17 ++- 4 files changed, 115 insertions(+), 80 deletions(-) diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index ad7f7d405c..181f8a206e 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -1183,16 +1183,16 @@ class ModelAdmin(BaseModelAdmin): inline_admin_formsets.append(inline_admin_formset) media = media + inline_admin_formset.media - context = { - 'title': _('Add %s') % force_text(opts.verbose_name), - 'adminform': adminForm, - 'is_popup': IS_POPUP_VAR in request.REQUEST, - 'media': media, - 'inline_admin_formsets': inline_admin_formsets, - 'errors': helpers.AdminErrorList(form, formsets), - 'app_label': opts.app_label, - 'preserved_filters': self.get_preserved_filters(request), - } + context = dict(self.admin_site.each_context(), + title=_('Add %s') % force_text(opts.verbose_name), + adminform=adminForm, + is_popup=IS_POPUP_VAR in request.REQUEST, + media=media, + inline_admin_formsets=inline_admin_formsets, + errors=helpers.AdminErrorList(form, formsets), + app_label=opts.app_label, + preserved_filters=self.get_preserved_filters(request), + ) context.update(extra_context or {}) return self.render_change_form(request, context, form_url=form_url, add=True) @@ -1254,18 +1254,18 @@ class ModelAdmin(BaseModelAdmin): inline_admin_formsets.append(inline_admin_formset) media = media + inline_admin_formset.media - context = { - 'title': _('Change %s') % force_text(opts.verbose_name), - 'adminform': adminForm, - 'object_id': object_id, - 'original': obj, - 'is_popup': IS_POPUP_VAR in request.REQUEST, - 'media': media, - 'inline_admin_formsets': inline_admin_formsets, - 'errors': helpers.AdminErrorList(form, formsets), - 'app_label': opts.app_label, - 'preserved_filters': self.get_preserved_filters(request), - } + context = dict(self.admin_site.each_context(), + title=_('Change %s') % force_text(opts.verbose_name), + adminform=adminForm, + object_id=object_id, + original=obj, + is_popup=IS_POPUP_VAR in request.REQUEST, + media=media, + inline_admin_formsets=inline_admin_formsets, + errors=helpers.AdminErrorList(form, formsets), + app_label=opts.app_label, + preserved_filters=self.get_preserved_filters(request), + ) context.update(extra_context or {}) return self.render_change_form(request, context, change=True, obj=obj, form_url=form_url) @@ -1400,23 +1400,23 @@ class ModelAdmin(BaseModelAdmin): selection_note_all = ungettext('%(total_count)s selected', 'All %(total_count)s selected', cl.result_count) - context = { - 'module_name': force_text(opts.verbose_name_plural), - 'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)}, - 'selection_note_all': selection_note_all % {'total_count': cl.result_count}, - 'title': cl.title, - 'is_popup': cl.is_popup, - 'cl': cl, - 'media': media, - 'has_add_permission': self.has_add_permission(request), - 'opts': cl.opts, - 'app_label': app_label, - 'action_form': action_form, - 'actions_on_top': self.actions_on_top, - 'actions_on_bottom': self.actions_on_bottom, - 'actions_selection_counter': self.actions_selection_counter, - 'preserved_filters': self.get_preserved_filters(request), - } + context = dict(self.admin_site.each_context(), + module_name=force_text(opts.verbose_name_plural), + selection_note=_('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)}, + selection_note_all=selection_note_all % {'total_count': cl.result_count}, + title=cl.title, + is_popup=cl.is_popup, + cl=cl, + media=media, + has_add_permission=self.has_add_permission(request), + opts=cl.opts, + app_label=app_label, + action_form=action_form, + actions_on_top=self.actions_on_top, + actions_on_bottom=self.actions_on_bottom, + actions_selection_counter=self.actions_selection_counter, + preserved_filters=self.get_preserved_filters(request), + ) context.update(extra_context or {}) return TemplateResponse(request, self.change_list_template or [ @@ -1483,17 +1483,17 @@ class ModelAdmin(BaseModelAdmin): else: title = _("Are you sure?") - context = { - "title": title, - "object_name": object_name, - "object": obj, - "deleted_objects": deleted_objects, - "perms_lacking": perms_needed, - "protected": protected, - "opts": opts, - "app_label": app_label, - 'preserved_filters': self.get_preserved_filters(request), - } + context = dict(self.admin_site.each_context(), + title=title, + object_name=object_name, + object=obj, + deleted_objects=deleted_objects, + perms_lacking=perms_needed, + protected=protected, + opts=opts, + app_label=app_label, + preserved_filters=self.get_preserved_filters(request), + ) context.update(extra_context or {}) return TemplateResponse(request, self.delete_confirmation_template or [ @@ -1520,15 +1520,15 @@ class ModelAdmin(BaseModelAdmin): content_type__id__exact=ContentType.objects.get_for_model(model).id ).select_related().order_by('action_time') - context = { - 'title': _('Change history: %s') % force_text(obj), - 'action_list': action_list, - 'module_name': capfirst(force_text(opts.verbose_name_plural)), - 'object': obj, - 'app_label': app_label, - 'opts': opts, - 'preserved_filters': self.get_preserved_filters(request), - } + context = dict(self.admin_site.each_context(), + title=_('Change history: %s') % force_text(obj), + action_list=action_list, + module_name=capfirst(force_text(opts.verbose_name_plural)), + object=obj, + app_label=app_label, + opts=opts, + preserved_filters=self.get_preserved_filters(request), + ) context.update(extra_context or {}) return TemplateResponse(request, self.object_history_template or [ "admin/%s/%s/object_history.html" % (app_label, opts.model_name), diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index 91b805e513..67ed3bba4e 100644 --- a/django/contrib/admin/sites.py +++ b/django/contrib/admin/sites.py @@ -34,6 +34,16 @@ class AdminSite(object): functions that present a full admin interface for the collection of registered models. """ + + # Text to put at the end of each page's . + site_title = _('Django site admin') + + # Text to put in each page's <h1>. + site_header = _('Django administration') + + # Text to put at the top of the admin index page. + index_title = _('Site administration') + login_form = None index_template = None app_index_template = None @@ -236,6 +246,16 @@ class AdminSite(object): def urls(self): return self.get_urls(), self.app_name, self.name + def each_context(self): + """ + Returns a dictionary of variables to put in the template context for + *every* page in the admin site. + """ + return { + 'site_title': self.site_title, + 'site_header': self.site_header, + } + def password_change(self, request): """ Handles the "change password" task -- both form display and validation. @@ -244,7 +264,8 @@ class AdminSite(object): url = reverse('admin:password_change_done', current_app=self.name) defaults = { 'current_app': self.name, - 'post_change_redirect': url + 'post_change_redirect': url, + 'extra_context': self.each_context(), } if self.password_change_template is not None: defaults['template_name'] = self.password_change_template @@ -257,7 +278,7 @@ class AdminSite(object): from django.contrib.auth.views import password_change_done defaults = { 'current_app': self.name, - 'extra_context': extra_context or {}, + 'extra_context': dict(self.each_context(), **(extra_context or {})), } if self.password_change_done_template is not None: defaults['template_name'] = self.password_change_done_template @@ -286,7 +307,7 @@ class AdminSite(object): from django.contrib.auth.views import logout defaults = { 'current_app': self.name, - 'extra_context': extra_context or {}, + 'extra_context': dict(self.each_context(), **(extra_context or {})), } if self.logout_template is not None: defaults['template_name'] = self.logout_template @@ -298,11 +319,11 @@ class AdminSite(object): Displays the login form for the given HttpRequest. """ from django.contrib.auth.views import login - context = { - 'title': _('Log in'), - 'app_path': request.get_full_path(), - REDIRECT_FIELD_NAME: request.get_full_path(), - } + context = dict(self.each_context(), + title=_('Log in'), + app_path=request.get_full_path(), + ) + context[REDIRECT_FIELD_NAME] = request.get_full_path() context.update(extra_context or {}) defaults = { @@ -366,10 +387,10 @@ class AdminSite(object): for app in app_list: app['models'].sort(key=lambda x: x['name']) - context = { - 'title': _('Site administration'), - 'app_list': app_list, - } + context = dict(self.each_context(), + title=self.index_title, + app_list=app_list, + ) context.update(extra_context or {}) return TemplateResponse(request, self.index_template or 'admin/index.html', context, @@ -420,11 +441,11 @@ class AdminSite(object): raise Http404('The requested admin page does not exist.') # Sort the models alphabetically within each app. app_dict['models'].sort(key=lambda x: x['name']) - context = { - 'title': _('%s administration') % capfirst(app_label), - 'app_list': [app_dict], - 'app_label': app_label, - } + context = dict(self.each_context(), + title=_('%s administration') % capfirst(app_label), + app_list=[app_dict], + app_label=app_label, + ) context.update(extra_context or {}) return TemplateResponse(request, self.app_index_template or [ diff --git a/django/contrib/admin/templates/admin/base_site.html b/django/contrib/admin/templates/admin/base_site.html index b867bd29bd..fa8ea2a352 100644 --- a/django/contrib/admin/templates/admin/base_site.html +++ b/django/contrib/admin/templates/admin/base_site.html @@ -1,10 +1,9 @@ {% extends "admin/base.html" %} -{% load i18n %} -{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %} +{% block title %}{{ title }} | {{ site_title }}{% endblock %} {% block branding %} -<h1 id="site-name">{% trans 'Django administration' %}</h1> +<h1 id="site-name">{{ site_header }}</h1> {% endblock %} {% block nav-global %}{% endblock %} diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index ba5fa3bff6..4a96d73604 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -2162,7 +2162,7 @@ creating your own ``AdminSite`` instance (see below), and changing the Python class), and register your models and ``ModelAdmin`` subclasses with it instead of using the default. - When constructing an instance of an ``AdminSite``, you are able to provide + When constructing an instance of an ``AdminSite``, you can provide a unique instance name using the ``name`` argument to the constructor. This instance name is used to identify the instance, especially when :ref:`reversing admin URLs <admin-reverse-urls>`. If no instance name is @@ -2174,6 +2174,21 @@ creating your own ``AdminSite`` instance (see below), and changing the Templates can override or extend base admin templates as described in `Overriding Admin Templates`_. +.. versionadded:: 1.6 +.. attribute:: AdminSite.site_header + The text to put at the top of each admin page, as an ``<h1>`` (a string). + By default, this is "Django administration". + +.. versionadded:: 1.6 +.. attribute:: AdminSite.site_title + The text to put at the end of each admin page's ``<title>`` (a string). By + default, this is "Django site admin". + +.. versionadded:: 1.6 +.. attribute:: AdminSite.index_title + The text to put at the top of the admin index page (a string). By default, + this is "Site administration". + .. attribute:: AdminSite.index_template Path to a custom template that will be used by the admin site main index