Openstack -- Horizon二次开发(一)

Horizon二次开发

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

实际结果:
Openstack -- Horizon二次开发(一)_第1张图片

DataTableView

官网上给出了通用视图DataTableView的介绍:
http://docs.openstack.org/developer/horizon/topics/tables.html

DataTableView使用三要素:

  • table_class,需要新建的表的名称
  • template_name,显示模板
  • get_data(), 获取数据方法

用户可以通过实现这三者轻松实现数据表格显示。

类似于上面新建一个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 %}

实际结果:
Openstack -- Horizon二次开发(一)_第2张图片

MultiTableView

http://docs.openstack.org/developer/horizon/ref/tables.html
视图MultiTableView与DataTableView很类似,不同之处在于一个页面中显示多个表,实现上也有不同,MultiTableView使用三要素:

  • table_classes,需要新建的表的名称赋值为一个tuple
  • template_name,显示模板
  • get_{{ table_name }}_data(), 为每个表定义出获取数据方法

类似于上面新建一个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 %}

实际效果:
Openstack -- Horizon二次开发(一)_第3张图片

Horizon中dashboard开发是一种注册的理念,新建dashboard mydashboard在enable中配置添加mydashboard,再在新建的mydashboard中新建panel,并且在mydashboard.dashboard.py文件中注册panel。

你可能感兴趣的:(openstack)