Skip to content

Commit

Permalink
Added AdminSite attributes for easily changing admin title.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
adrianholovaty committed Sep 6, 2013
1 parent 273a1e6 commit a962286
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 80 deletions.
118 changes: 59 additions & 59 deletions django/contrib/admin/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -1183,16 +1183,16 @@ def add_view(self, request, form_url='', extra_context=None):
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)

Expand Down Expand Up @@ -1254,18 +1254,18 @@ def change_view(self, request, object_id, form_url='', extra_context=None):
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)

Expand Down Expand Up @@ -1400,23 +1400,23 @@ def changelist_view(self, request, extra_context=None):
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 [
Expand Down Expand Up @@ -1483,17 +1483,17 @@ def delete_view(self, request, object_id, extra_context=None):
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 [
Expand All @@ -1520,15 +1520,15 @@ def history_view(self, request, object_id, extra_context=None):
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),
Expand Down
55 changes: 38 additions & 17 deletions django/contrib/admin/sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 <title>.
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
Expand Down Expand Up @@ -236,6 +246,16 @@ def wrapper(*args, **kwargs):
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.
Expand All @@ -244,7 +264,8 @@ def password_change(self, request):
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
Expand All @@ -257,7 +278,7 @@ def password_change_done(self, request, extra_context=None):
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
Expand Down Expand Up @@ -286,7 +307,7 @@ def logout(self, request, extra_context=None):
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
Expand All @@ -298,11 +319,11 @@ def login(self, request, extra_context=None):
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 = {
Expand Down Expand Up @@ -366,10 +387,10 @@ def index(self, request, extra_context=None):
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,
Expand Down Expand Up @@ -420,11 +441,11 @@ def app_index(self, request, app_label, extra_context=None):
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 [
Expand Down
5 changes: 2 additions & 3 deletions django/contrib/admin/templates/admin/base_site.html
Original file line number Diff line number Diff line change
@@ -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 %}
17 changes: 16 additions & 1 deletion docs/ref/contrib/admin/index.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

This comment has been minimized.

Copy link
@timgraham

timgraham Sep 6, 2013

Member

Couple of issues here:

  1. we're on 1.7 now
  2. these docs are formatted weirdly when you build them. I think . . versionadded:: 1.6 should probably go below each ..attribute::
  3. We try to add new features to the release notes as well

I can fix all this if you want.

p.s. After doing things "the hard way" in the tutorial, we could point out this feature there as well.

This comment has been minimized.

Copy link
@adrianholovaty

adrianholovaty Sep 6, 2013

Author Member

Thanks for the thoughts!

  1. I'm backporting it to 1.6.
  2. Will fix that -- thanks.
  3. Yup, I know. Working on it. Not sure yet whether I'll change the tutorial bit, because that section appears to double as an introduction to template overriding, so it may not be worth removing.
.. 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
Expand Down

2 comments on commit a962286

@evildmp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces a problem with some auth templates - https://code.djangoproject.com/ticket/21293.

@aaugustin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This problem is blocking the 1.7 release.

@adrianholovaty Would you have a few minutes to take a look at the ticket?

Please sign in to comment.