Openstack官网上给出了一个Horizon二次开发是示例:
http://docs.openstack.org/developer/horizon/tutorials/dashboard.html
可以按照官网上示例逐步进行,完成一个自己开发的dashboard。对mypanel中的views.py代码稍作修改:
class IndexView(tabs.TabbedTableView):
tab_group_class = mydashboard_tabs.MypanelTabs
template_name = 'mydashboard/mypanel/index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['content'] = 'test code'
return context
和Django中通用试图类似,这样就可以往前端传递content参数。
值得注意的是:
class InstanceTab(tabs.TableTab):
table_classes = (tables.InstancesTable,)
def get_instances_data(self):
pass
方法get_instances_data定义是用来获取表的tab数据,此方法定义必须遵从get_{{ table_name }}_data的方式,table_name就是InstancesTable的Meta中name,在官网:
http://docs.openstack.org/developer/horizon/ref/tabs.html 中有介绍。
TabbedTableView视图从tables.MultiTableMixin, TabView继承来,在MultiTableMixin基类中定义了get_tables方法如下:
def get_tables(self):
if not self.table_classes:
raise AttributeError('You must specify one or more DataTable '
'classes for the "table_classes" attribute '
'on %s.' % self.__class__.__name__)
if not self._tables:
for table in self.table_classes:
if not has_permissions(self.request.user,
table._meta):
continue
func_name = "get_%s_table" % table._meta.name #此处就是自定的 get_instances_data 方法绑定处
table_func = getattr(self, func_name, None)
if table_func is None:
tbl = table(self.request, **self.kwargs)
else:
tbl = table_func(self, self.request, **self.kwargs)
self._tables[table._meta.name] = tbl
return self._tables
官网上给出了通用视图DataTableView的介绍:
http://docs.openstack.org/developer/horizon/topics/tables.html
DataTableView使用三要素:
用户可以通过实现这三者轻松实现数据表格显示。
类似于上面新建一个datatable panel,目录结构如下:
datatable
├── __init__.py
├── panel.py
├── tables.py
├── templates
│ └── datatable
│ └── index.html
├── tests.py
├── urls.py
└── views.py
其中tables.py内容与mypanel/tables.py中一样,views.py内容如下:
from horizon import tables, exceptions
from tables import InstancesTable
from openstack_dashboard import api
class IndexView(tables.DataTableView):
table_class = InstancesTable
template_name = 'mydashboard/datatable/index.html'
def get_data(self, *args, **kwargs):
try:
marker = self.request.GET.get(
InstancesTable._meta.pagination_param, None)
instances,self._has_more = api.nova.server_list(
self.request,
search_opts = {'marker': marker,'paginate': True})
if self.request.GET.get('filter', False):
instances = [i for i in instances if self.request.GET['filter'] in i.name]
return instances
except Exception:
self._has_more = False
error_message = _('Unable to get instances')
exceptions.handle(self.request, error_message)
return []
模板mydashboard/datatable/index.html:
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Datatable" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Datatable") %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12 datable">
{{ table.render }}
div>
div>
{% endblock %}
http://docs.openstack.org/developer/horizon/ref/tables.html
视图MultiTableView与DataTableView很类似,不同之处在于一个页面中显示多个表,实现上也有不同,MultiTableView使用三要素:
类似于上面新建一个multidatatable panel,目录结构如下:
multidatatable
├── init.py
├── panel.py
├── tables.py
├── templates
│ └── multidatatable
│ └── index.html
├── tests.py
├── urls.py
└── views.py
表定义文件tables.py文件中内容:
from django.utils.translation import ugettext_lazy as _
from horizon import tables
#定义两个表InstancesTable和TenantsTable
class InstancesTable(tables.DataTable):
name = tables.Column("name", verbose_name=_("Name"))
created = tables.Column("created", verbose_name=_("Created"))
instance_name = tables.Column("OS-EXT-SRV-ATTR:instance_name",
verbose_name=_("Instance Name"))
zone = tables.Column('availability_zone',
verbose_name=_("Availability Zone"))
image_name = tables.Column('image_name', verbose_name=_("Image Name"))
class Meta:
name = "instances"
verbose_name = _("Instances")
class TenantsTable(tables.DataTable):
name = tables.Column('name', verbose_name=_('Name'))
id = tables.Column('id', verbose_name=_('Project ID'))
enabled = tables.Column('enabled', verbose_name=_('Enabled'))
class Meta:
name = "tenants"
verbose_name = _("Tenants")
views.py中内容:
from horizon import tables, exceptions
from tables import InstancesTable, TenantsTable
from openstack_dashboard import policy
from openstack_dashboard import api
from horizon import messages
#分别实现获取数据方法get_instances_data和get_tenants_data
class IndexView(tables.MultiTableView):
table_classes = (InstancesTable, TenantsTable)
template_name = 'mydashboard/multidatatable/index.html'
def get_instances_data(self, *args, **kwargs):
try:
marker = self.request.GET.get(
InstancesTable._meta.pagination_param, None)
instances,self._has_more = api.nova.server_list(
self.request,
search_opts = {'marker': marker,'paginate': True})
if self.request.GET.get('filter', False):
instances = [i for i in instances if self.request.GET['filter'] in i.name]
return instances
except Exception:
self._has_more = False
error_message = _('Unable to get instances')
exceptions.handle(self.request, error_message)
return []
def get_tenants_data(self, *args, **kwargs):
tenants = []
marker = self.request.GET.get(
TenantsTable._meta.pagination_param, None)
self._more = False
if policy.check((("identity", "identity:list_projects"),),
self.request):
domain_context = api.keystone.get_effective_domain_id(self.request)
try:
tenants, self._more = api.keystone.tenant_list(
self.request,
domain=domain_context,
paginate=True,
marker=marker)
except Exception:
exceptions.handle(self.request,
_("Unable to retrieve project list."))
elif policy.check((("identity", "identity:list_user_projects"),),
self.request):
try:
tenants, self._more = api.keystone.tenant_list(
self.request,
user=self.request.user.id,
paginate=True,
marker=marker,
admin=False)
except Exception:
exceptions.handle(self.request,
_("Unable to retrieve project information."))
else:
msg = \
_("Insufficient privilege level to view project information.")
messages.info(self.request, msg)
if api.keystone.VERSIONS.active >= 3:
domain_lookup = api.keystone.domain_lookup(self.request)
for t in tenants:
t.domain_name = domain_lookup.get(t.domain_id)
return tenants
前端模板不是用{{ table.render }}取而代之是{{ {table_name}_table.render }}标签,示例如下:
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Multidatatable" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Multidatatable") %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12 multitable">
{{ instances_table.render }}
div>
<div class="col-sm-12 multitable">
{{ tenants_table.render }}
div>
div>
{% endblock %}
Horizon中dashboard开发是一种注册的理念,新建dashboard mydashboard在enable中配置添加mydashboard,再在新建的mydashboard中新建panel,并且在mydashboard.dashboard.py文件中注册panel。