Reduced code duplication in creating page headers

The same line of code to add a page title to a template was repeated in
many templates, this patch moves that line into the base.html, and also
tries to standardize the way page titles are defined in the python.

Change-Id: I11367d3007ebae727ba45446076a31307d477995
Closes-Bug: 1399840
This commit is contained in:
Sam Betts 2014-12-18 10:21:22 +00:00
parent c7123d3f57
commit 1934a7eaa8
40 changed files with 151 additions and 136 deletions

View File

@ -18,9 +18,9 @@ import os
from django.conf import settings
from django import http
from django.utils.translation import ugettext_lazy as _
from django.views import generic
from horizon import exceptions
from horizon import views
ADD_TO_FIELD_HEADER = "HTTP_X_HORIZON_ADD_TO_FIELD"
@ -77,7 +77,7 @@ class ModalFormMixin(object):
return context
class ModalFormView(ModalBackdropMixin, ModalFormMixin, generic.FormView):
class ModalFormView(ModalBackdropMixin, ModalFormMixin, views.HorizonFormView):
"""The main view class from which all views which handle forms in Horizon
should inherit. It takes care of all details with processing
:class:`~horizon.forms.base.SelfHandlingForm` classes, and modal concerns

View File

@ -15,7 +15,8 @@
from collections import defaultdict
from django import shortcuts
from django.views import generic
from horizon import views
from horizon.templatetags.horizon import has_permissions # noqa
@ -125,7 +126,7 @@ class MultiTableMixin(object):
return handled
class MultiTableView(MultiTableMixin, generic.TemplateView):
class MultiTableView(MultiTableMixin, views.HorizonTemplateView):
"""A class-based generic view to handle the display and processing of
multiple :class:`~horizon.tables.DataTable` classes in a single view.
@ -136,6 +137,7 @@ class MultiTableView(MultiTableMixin, generic.TemplateView):
which returns a set of data for that table; and specify a template for
the ``template_name`` attribute.
"""
def construct_tables(self):
tables = self.get_tables().values()
# Early out before data is loaded

View File

@ -11,14 +11,14 @@
# under the License.
from django import http
from django.views import generic
from horizon import exceptions
from horizon import tables
from horizon.tabs.base import TableTab # noqa
from horizon import views
class TabView(generic.TemplateView):
class TabView(views.HorizonTemplateView):
"""A generic class-based view for displaying a
:class:`horizon.tabs.TabGroup`.

View File

@ -33,7 +33,9 @@
<div id='content_body'>
<div class="row">
<div class="col-xs-12">
{% block page_header %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock %}
{% block main %}{% endblock %}
</div>
</div>

View File

@ -0,0 +1,92 @@
# Copyright 2015 Cisco Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from horizon.test import helpers as test
from horizon import views
from django import forms
from django.test import client
from django.views import generic
FAKENAME = "FakeName"
class ViewData(object):
template_name = 'fake'
def get_context_data(self, **kwargs):
context = super(ViewData, self).get_context_data(**kwargs)
context['object'] = {'name': 'myName'}
return context
class PageWithNoTitle(ViewData, views.HorizonTemplateView):
pass
class PageWithTitle(ViewData, views.HorizonTemplateView):
page_title = "A Title"
class PageWithTitleData(ViewData, views.HorizonTemplateView):
page_title = "A Title: {{ object.name }}"
class FormWithTitle(ViewData, views.HorizonFormView):
form_class = forms.Form
page_title = "A Title: {{ object.name }}"
class ViewWithTitle(views.PageTitleMixin, generic.TemplateView):
page_title = "Fake"
class PageTitleTests(test.TestCase):
def setUp(self):
super(PageTitleTests, self).setUp()
self.request = client.RequestFactory().get('fake')
def _dispatch(self, viewClass):
p = viewClass()
p.request = self.request
return p.dispatch(self.request)
def test_render_title(self):
tm = ViewWithTitle()
context = tm.render_title({})
self.assertEqual("Fake", context['page_title'])
def test_render_title_override(self):
tm = ViewWithTitle()
context = tm.render_title({'page_title': "ekaF"})
self.assertEqual("ekaF", context['page_title'])
def test_no_title_set(self):
res = self._dispatch(PageWithNoTitle)
self.assertEqual("", res.context_data['page_title'])
def test_title_set(self):
res = self._dispatch(PageWithTitle)
self.assertEqual("A Title", res.context_data['page_title'])
def test_title_with_data(self):
res = self._dispatch(PageWithTitleData)
self.assertEqual("A Title: myName", res.context_data['page_title'])
def test_form_with_title(self):
res = self._dispatch(FormWithTitle)
self.assertEqual("A Title: myName", res.context_data['page_title'])

View File

@ -13,18 +13,44 @@
# under the License.
from django import shortcuts
from django import template
from django.views import generic
import horizon
from horizon import exceptions
class PageTitleMixin(object):
page_title = ""
def render_title(self, context):
if "page_title" not in context:
con = template.Context(context)
# NOTE(sambetts): Cast to unicode to ensure lazy translations
# are handled correctly.
temp = template.Template(unicode(self.page_title))
context["page_title"] = temp.render(con)
return context
def render_to_response(self, context):
context = self.render_title(context)
return super(PageTitleMixin, self).render_to_response(context)
class HorizonTemplateView(PageTitleMixin, generic.TemplateView):
pass
class HorizonFormView(PageTitleMixin, generic.FormView):
pass
def user_home(request):
"""Reversible named view to direct a user to the appropriate homepage."""
return shortcuts.redirect(horizon.get_user_home(request.user))
class APIView(generic.TemplateView):
class APIView(HorizonTemplateView):
"""A quick class-based view for putting API data into a template.
Subclasses must define one method, ``get_data``, and a template name
@ -34,6 +60,7 @@ class APIView(generic.TemplateView):
the :func:`horizon.exceptions.handle` error handler if not otherwise
caught.
"""
def get_data(self, request, context, *args, **kwargs):
"""This method should handle any necessary API calls, update the
context object, and return the context object at the end.

View File

@ -3,10 +3,6 @@
{% block title %}{% trans "Namespace Details" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Namespace Details: ")|add:namespace.namespace|default:_("None") %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -86,9 +86,9 @@ class CreateView(forms.ModalFormView):
class DetailView(tabs.TabView):
redirect_url = constants.METADATA_INDEX_URL
tab_group_class = admin_tabs.NamespaceDetailTabs
template_name = constants.METADATA_DETAIL_TEMPLATE
page_title = _("Namespace Details: {{ namespace.namespace }}")
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Usage Overview" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Overview") %}
{% endblock page_header %}
{% block main %}
{% if monitoring %}
<div id="monitoring">

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Volume Details" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -28,14 +28,6 @@ from openstack_dashboard.dashboards.project.volumes.volumes \
class DetailView(volumes_views.DetailView):
template_name = "admin/volumes/volumes/detail.html"
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
volume = context["volume"]
context["page_title"] = _("Volume Details: "
"%(volume_name)s") % {'volume_name':
volume.name}
return context
def get_redirect_url(self):
return reverse('horizon:admin:volumes:index')

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans 'Group Management' %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
{{ group_members_table.render }}
{% endblock %}

View File

@ -120,14 +120,11 @@ class GroupManageMixin(object):
class ManageMembersView(GroupManageMixin, tables.DataTableView):
table_class = project_tables.GroupMembersTable
template_name = constants.GROUPS_MANAGE_VIEW_TEMPLATE
page_title = _("Group Management: {{ group.name }}")
def get_context_data(self, **kwargs):
context = super(ManageMembersView, self).get_context_data(**kwargs)
group = self._get_group()
context['group'] = group
context['page_title'] = _("Group Management: "
"%(group_name)s") % {'group_name':
group.name}
context['group'] = self._get_group()
return context
def get_data(self):

View File

@ -40,6 +40,8 @@ from openstack_dashboard.dashboards.project.access_and_security.\
class DetailView(tables.DataTableView):
table_class = project_tables.RulesTable
template_name = 'project/access_and_security/security_groups/detail.html'
page_title = _("Manage Security Group Rules: "
"{{ security_group.name }} ({{ security_group.id }})")
@memoized.memoized_method
def _get_data(self):
@ -61,13 +63,7 @@ class DetailView(tables.DataTableView):
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
security_group = self._get_data()
security_group_name_id = "%s (%s)" % (security_group.name,
security_group.id)
context["security_group"] = security_group
context["page_title"] = _(
"Manage Security Group Rules: %(security_group)s") % {
'security_group': security_group_name_id}
context["security_group"] = self._get_data()
return context

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Manage Security Group Rules" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -2,10 +2,6 @@
{% load i18n sizeformat %}
{% block title %}{% trans "Backup Details" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -75,6 +75,7 @@ class BackupView(horizon_workflows.WorkflowView):
class DetailView(horizon_views.APIView):
template_name = "project/database_backups/details.html"
page_title = _("Backup Details: {{ backup.name }}")
def get_data(self, request, context, *args, **kwargs):
backup_id = kwargs.get("backup_id")
@ -103,8 +104,4 @@ class DetailView(horizon_views.APIView):
instance = None
context['backup'] = backup
context['instance'] = instance
context['page_title'] = _("Backup Details: "
"%(backup_name)s") % {'backup_name':
backup.name}
return context

View File

@ -2,10 +2,6 @@
{% load i18n sizeformat %}
{% block title %}{% trans "Instance Details" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -96,6 +96,7 @@ class LaunchInstanceView(horizon_workflows.WorkflowView):
class DetailView(horizon_tabs.TabbedTableView):
tab_group_class = tabs.InstanceDetailTabs
template_name = 'project/databases/detail.html'
page_title = _("Instance Details: {{ instance.name }}")
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
@ -104,9 +105,6 @@ class DetailView(horizon_tabs.TabbedTableView):
context["instance"] = instance
context["url"] = self.get_redirect_url()
context["actions"] = table.render_row_actions(instance)
context["page_title"] = _("Instance Details: "
"%(instance_name)s") % {'instance_name':
instance.name}
return context
@memoized.memoized_method

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Edit Firewall" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
{% include 'project/firewalls/_updatefirewall.html' %}
{% endblock %}

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Edit Policy" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
{% include 'project/firewalls/_updatepolicy.html' %}
{% endblock %}

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Edit Rule" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
{% include 'project/firewalls/_updaterule.html' %}
{% endblock %}

View File

@ -121,12 +121,12 @@ class UpdateRuleView(forms.ModalFormView):
template_name = "project/firewalls/updaterule.html"
context_object_name = 'rule'
success_url = reverse_lazy("horizon:project:firewalls:index")
page_title = _("Edit Rule")
def get_context_data(self, **kwargs):
context = super(UpdateRuleView, self).get_context_data(**kwargs)
context['rule_id'] = self.kwargs['rule_id']
obj = self._get_object()
context['page_title'] = _("Edit Rule")
if obj:
context['name'] = obj.name_or_id
context['page_title'] = _("Edit Rule "
@ -159,12 +159,12 @@ class UpdatePolicyView(forms.ModalFormView):
template_name = "project/firewalls/updatepolicy.html"
context_object_name = 'policy'
success_url = reverse_lazy("horizon:project:firewalls:index")
page_title = _("Edit Policy")
def get_context_data(self, **kwargs):
context = super(UpdatePolicyView, self).get_context_data(**kwargs)
context["policy_id"] = self.kwargs['policy_id']
obj = self._get_object()
context['page_title'] = _("Edit Policy")
if obj:
context['name'] = obj.name_or_id
context['page_title'] = _("Edit Policy %s") % obj.name
@ -192,12 +192,12 @@ class UpdateFirewallView(forms.ModalFormView):
template_name = "project/firewalls/updatefirewall.html"
context_object_name = 'firewall'
success_url = reverse_lazy("horizon:project:firewalls:index")
page_title = _("Edit Firewall")
def get_context_data(self, **kwargs):
context = super(UpdateFirewallView, self).get_context_data(**kwargs)
context["firewall_id"] = self.kwargs['firewall_id']
obj = self._get_object()
context['page_title'] = _("Edit Firewall")
if obj:
context['name'] = obj.name
context['page_title'] = _("Edit Firewall %s") % obj.name

View File

@ -83,6 +83,7 @@ class UpdateView(forms.ModalFormView):
class DetailView(tabs.TabView):
tab_group_class = project_tabs.ImageDetailTabs
template_name = 'project/images/images/detail.html'
page_title = _("Image Details: {{ image.name }}")
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
@ -91,9 +92,6 @@ class DetailView(tabs.TabView):
context["image"] = image
context["url"] = self.get_redirect_url()
context["actions"] = table.render_row_actions(image)
context["page_title"] = _("Image Details: "
"%(image_name)s") % {'image_name':
image.name}
return context
@staticmethod

View File

@ -3,10 +3,6 @@
{% block title %}{% trans "Image Details"%}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -2,10 +2,6 @@
{% load i18n sizeformat %}
{% block title %}{% trans "Instance Details" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -252,6 +252,7 @@ class DetailView(tabs.TabView):
tab_group_class = project_tabs.InstanceDetailTabs
template_name = 'project/instances/detail.html'
redirect_url = 'horizon:project:instances:index'
page_title = _("Instance Details: {{ instance.name }}")
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
@ -260,9 +261,6 @@ class DetailView(tabs.TabView):
table = project_tables.InstancesTable(self.request)
context["url"] = reverse(self.redirect_url)
context["actions"] = table.render_row_actions(instance)
context["page_title"] = _("Instance Details: "
"%(instance_name)s") % {'instance_name':
instance.name}
return context
@memoized.memoized_method

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Network Details"%}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -94,6 +94,7 @@ class UpdateView(forms.ModalFormView):
class DetailView(tables.MultiTableView):
table_classes = (subnet_tables.SubnetsTable, port_tables.PortsTable)
template_name = 'project/networks/detail.html'
page_title = _("Network Details: {{ network.name }}")
def get_subnets_data(self):
try:
@ -136,9 +137,6 @@ class DetailView(tables.MultiTableView):
table = project_tables.NetworksTable(self.request)
context["url"] = self.get_redirect_url()
context["actions"] = table.render_row_actions(network)
context["page_title"] = _("Network Details: "
"%(network_name)s") % {'network_name':
network.name}
return context
@staticmethod

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Instance Overview" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Overview") %}
{% endblock page_header %}
{% block main %}
{% include "horizon/common/_limit_summary.html" %}

View File

@ -2,10 +2,6 @@
{% load i18n sizeformat %}
{% block title %}{% trans "Stack Details" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -2,10 +2,6 @@
{% load i18n sizeformat %}
{% block title %}{% trans "Resource Details" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -196,6 +196,7 @@ class EditStackView(CreateStackView):
class DetailView(tabs.TabView):
tab_group_class = project_tabs.StackDetailTabs
template_name = 'project/stacks/detail.html'
page_title = _("Stack Details: {{ stack.stack_name }}")
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
@ -204,9 +205,6 @@ class DetailView(tabs.TabView):
context["stack"] = stack
context["url"] = self.get_redirect_url()
context["actions"] = table.render_row_actions(stack)
context["page_title"] = _("Stack Details: "
"%(stack_name)s") % {'stack_name':
stack.stack_name}
return context
@memoized.memoized_method

View File

@ -45,6 +45,7 @@ class CreateBackupView(forms.ModalFormView):
class BackupDetailView(tabs.TabView):
tab_group_class = backup_tabs.BackupDetailTabs
template_name = 'project/volumes/backups/detail.html'
page_title = _("Volume Backup Details: {{ backup.name }}")
def get_context_data(self, **kwargs):
context = super(BackupDetailView, self).get_context_data(**kwargs)
@ -53,10 +54,6 @@ class BackupDetailView(tabs.TabView):
context["backup"] = backup
context["url"] = self.get_redirect_url()
context["actions"] = table.render_row_actions(backup)
context["page_title"] = _("Volume Backup Details: "
"%(backup_name)s") % {'backup_name':
backup.name}
return context
@memoized.memoized_method

View File

@ -61,6 +61,7 @@ class UpdateView(forms.ModalFormView):
class DetailView(tabs.TabView):
tab_group_class = vol_snapshot_tabs.SnapshotDetailTabs
template_name = 'project/volumes/snapshots/detail.html'
page_title = _("Volume Snapshot Details: {{ snapshot.name }}")
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
@ -69,9 +70,6 @@ class DetailView(tabs.TabView):
context["snapshot"] = snapshot
context["url"] = self.get_redirect_url()
context["actions"] = table.render_row_actions(snapshot)
context["page_title"] = _("Volume Snapshot Details: "
"%(snapshot_name)s") % {'snapshot_name':
snapshot.name}
return context
@memoized.memoized_method

View File

@ -2,9 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Volume Backup Details" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -2,9 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Volume Snapshot Details" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -2,10 +2,6 @@
{% load i18n %}
{% block title %}{% trans "Volume Details" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=page_title %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">

View File

@ -43,6 +43,7 @@ from openstack_dashboard.dashboards.project.volumes \
class DetailView(tabs.TabView):
tab_group_class = project_tabs.VolumeDetailTabs
template_name = 'project/volumes/volumes/detail.html'
page_title = _("Volume Details: {{ volume.name }}")
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
@ -51,10 +52,6 @@ class DetailView(tabs.TabView):
context["volume"] = volume
context["url"] = self.get_redirect_url()
context["actions"] = table.render_row_actions(volume)
context["page_title"] = _("Volume Details: "
"%(volume_name)s") % {'volume_name':
volume.name}
return context
@memoized.memoized_method

View File

@ -22,6 +22,7 @@ class UsageView(tables.DataTableView):
usage_class = None
show_terminated = True
csv_template_name = None
page_title = _("Overview")
def __init__(self, *args, **kwargs):
super(UsageView, self).__init__(*args, **kwargs)
@ -72,6 +73,7 @@ class UsageView(tables.DataTableView):
response_kwargs.setdefault("filename", "usage.csv")
else:
render_class = self.response_class
context = self.render_title(context)
resp = render_class(request=self.request,
template=self.get_template_names(),
context=context,