【翻译】Building on Horizon

注:openstack horion项目和其余的项目有所不一样,它主要提供一套工具,咱们能够本身定制开发咱们想要的dashboard(控制面板)。 javascript

翻译自:http://docs.openstack.org/developer/horizon/topics/tutorial.html css


本教程讨论如何使用Horizon中多样的组件来创建一个dashboard和panel经过 数据表和tabs。 html

做为例子,咱们讲以Nova 实例化API为基础来建立一个新的可视化的dashboard经过一个"floking"面板经过不一样的方表示实例的数据。 java

你能够找到一个参考实现的的代码在github https://github.com/gabrielhurley/horizon_demo. python

注意:你或许须要先阅读一些有帮助的资源,由于这是一个高级的教程。例如,你或许想开始Horizon quickstart guide 或者 Django tutorial. git

建立一个 dashboard(控制面板)

注意:你能够建立一个panel而不是dashboard,而后整合它到一个已经存在的dashboard。看章节overrides 。 github

快速版本

Horizon 提供了一套自定义管理命令来建立一个典型的基于dashboard的结构。下列的命令生成了大部分的模板代码: ajax

./run_tests.sh -m sstartdash visualizations
很是推荐你阅读剩余的章节来理解这个命令建立了什么和为何要建立。


结构

dashboard(或者panel)推荐的结构适合于典型的Django应用布局。咱们将命名咱们的dashboard "visualizations": shell

visualizations
  |--__init__.py
  |--dashboard.py
  |--templates/
  |--static/
dashboard.py模块将经过使用Horizon包含咱们要使用的dashboard类;templates和static目录分别是咱们的Django模板文件和静态媒体文件。


在static和templates目录中,不错的命名空间应该是像这样: django

templates/
  |--visualizations/
static/
  |--visualizations/
     |--css/
     |--js/
     |--img/
在那些文件和目录的地方,咱们能够继续写咱们本身的dashboard类。


定义一个dashboard

一个dashboard类能够极为简单(最少3行),至少定义一个name和一个slug:

import horizon

class VizDash(horizon.Dashboard):
    name = _("Visualizations")
    slug = "visualizations"

在实践中,一个dashboard类将一般包含更多的信息,例如一系列的panels。就是那些默认的panel,和任何访问dashboard的权限:

class VizDash(horizon.Dashboard):
    name = _("Visualizations")
    slug = "visualizations"
    panels = ('flocking',)
    default_panel = 'flocking'
    permissions = ('openstack.roles.admin')

从以前构建的例子咱们也能够想要定义一组panels共享一个主题并且在导航上有一个子标题:

class InstanceVisualizations(horizon.PanelGroup):
    slug = "instance_visualizations"
    name = _("Instance Visualizations")
    panels = ('flocking',)

class VizDash(horizon.Dashboard):
    name = _("Visualizations")
    slug = "visualizations"
    panels = (InstanceVisualizations,)
    default_panel = 'flocking'
    permissions = ('openstack.roles.admin',)
PanelGroup能够添加到dashboard类的panels列表就像 panels的slug那样。


一旦咱们的dashboard类完成,咱们须要作的是注册它:

horizon.register(VizDash)
这个操做的典型的位置是dashboard.py文件的底部,可是它能够在任何的其余地方,例如在一个重写的文件中。


建立一个panel

如今咱们已经有了咱们写的dashboard,咱们也能够建立咱们的panel。咱们讲称之为"flocking"。

注意:你不须要为了添加一个panel而写一个dashboard。这个结构是为了教程的完整性

快速版本

Horizon提供了一套自定义管理命令来建立一个典型的基于panel的结构。下面的命令生成大部分的模板代码:

./run_test.sh -m startpanel flocking --dashboard=visualizations --target=auto
dashboard参数是必选的,告诉命令panel注册的dashboard。target参数是可选的,auto意味着建立的panel文件应该在dashboard模块内相对于当前的目录(默认)。


很是推荐你阅读剩余的章节来理解这个命令建立了什么和为何要建立。

结构

一个Panel是一个相对flat结构,dashboard的panel的templates在dashboard的templates目录而不是在panel的templates目录。继续咱们的vizulaization/flocking例子,让咱们看看它们应该看起来像:

# stand-alone panel structure
flocking/
  |--__init__.py
  |--panel.py
  |--urls.py
  |--views.py
  |--templates/
     |--flocking/
        |--index.html

# panel-in-a-dashboard structure
visualizations/
|--__init__.py
|--dashboard.py
|--flocking/
   |--__init__.py
   |--panel.py
   |--urls.py
   |--views.py
|--templates/
   |--visualizations/
      |--flocking/
         |--index.html
跟随标准的Django命名规范。一样工做在Django的自动模板查找特性下。


定义一个panel

上面指定panel.py文件有一个特殊的意义。在一个dashboard中,任何模块的名字排列了panels属性在dashboard上将自动在panel.py文件中查找在相应的目录(详细状况有些神奇,可是被完全的审查在Django的admin代码库中)。

在panel.py模块中咱们定义咱们的 Panel类:

class Flocking(horizon.Panel):
    name = _("Flocking")
    slug = 'flocking'
简单吧?一旦咱们定义了它,咱们就在dashboard中注册它:



from visualizations import dashboard

dashboard.VizDash.register(Flocking)
简单! 你能够设置更多的可选的自定义项目在Panel类中,可是聪明的建议是想一下默认下应该有什么。


URls

一个充满智慧的设想就是Panel类能够被找到在一个urls.py文件在你的panel目录,咱们定义一个叫作index的视图做为panel的默认处理视图。下面是你的urls.py看起来应该像:

from django.conf.urls.defaults import patterns, url
from .views import IndexView

urlpatterns = patterns('',
    url(r'^$', IndexView.as_view(), name='index')
)
这不是100%标准的Django代码。这个例子(Horizon一般上)使用了基于类的视图在Django1.3中被介绍,使代码更加能重用。所以视图类被import在上面的例子中,as_view()方法被调用在URL pattern。


固然,假定你有一个视图类,而后带咱们到写panel中去。

Tables, Tabs, Views

如今咱们要去真正使人激动的部分了;在这以前的任何事情都是结构性的。

从高层次的视图开始,咱们最终的目标是建立一个视图(咱们的IndexView类)使用Horizion的DataTable类来展现数据,使用Horizon的TabGroup类给咱们一个用户友好的分页式的结构在浏览器中。

咱们将先开始table,整合它与tabs,而后创建咱们的视图。

定义一个table

Horizon提供了一个DataTable类简化了绝大多数的显示数据给最终用户。咱们这里只是浏览表面,可是它有一个巨大数量的能力。

这种状况下,咱们使用tables呈现数据,因此让咱们开始定义咱们的table(一个tables.py模块:

from horizon import tables

class FlockingInstancesTable(tables.DataTable):
    host = tables.Column("OS-EXT-SRV-ATTR:host", verbose_name=_("Host"))
    tenant = tables.Column('tenant_name', verbose_name=_("Tenant"))
    user = tables.Column('user_name', verbose_name=_("user"))
    vcpus = tables.Column('flavor_vcpus', verbose_name =_("VCPUs"))
    memory - tables.Column('flavor_memory', verbose_name=_("Memory"))
    age = tables.Column('age', verbose_name=_("Age"))

    class Meta:
        name = "instances"
        verbose_name = _("Instances")
有几件事情发生了,咱们建立了一个table子类,定义了六列。每列定义了它访问实例类的属性做为第一个参数,因为咱们但愿全部的事情都是能够被翻译的,咱们给没列一个verbose_name标记它们能够被翻译。


最后,咱们添加了一个Meta类定义了一些属性关于咱们的table,尤为是(翻译)verbose name,一个"slug"用来识别它。

注意:这里简化了实际中的实例对象的真是结构。访问flavor,tenant,用户属性须要另外一个步骤,这块的代码能够在代码示例中看到在github上。

定义tabs

由于咱们有了table,能够接受数据,咱们能够直接的到一个视图,可是咱们能够考虑跟多。在这种状况下咱们一样适用Horizon的TabGroup类。它给咱们一个干净,简化的tabs接口来显示咱们的可视化和能够的咱们的数据。

首先,创建咱们的tab

class VizTab(tabs.Tab)
    name = _("Visualization")
    slug = "viz"
    template_name = "visualizations/flocking/_flocking.html"

    def get_context_data(self, request):
        return None
这是你能作的最简单的。因为咱们的可视化将使用AJAX来加载数据咱们不须要传递任何内容到template上,全部咱们须要作的是定义个须要使用的template的名字。


如今,咱们须要给咱们的数据table一个tab:

from .tables import FlockingInstancesTable

class DataTab(tabs.TableTab):
    name = _("Data")
    slug = "data"
    table_classes = (FlockingInstancesTable,)
    preload = False

    def get_instances_data(self):
        try:
            instances = utils.get_instances_data(self.tab_group.request)
        except:
            instances = []
            exceptions.handle(self.tab_group.request, _('Unable to retrieve instance list.'))
        return instances


tab稍微有点复杂。最重要的,tab指定类型-处理数据tables(全部有关的特性)-它可使用preload属性来指定这个tab不该该被加载在默认的状况下。它将经过AJAX加载当有人点击它,保存咱们的API调用在绝大多数状况下。

最后,代码介绍了Horion中的错误处理的概念。horizon.exceptions.handle()功能集中的错误处理机制。

把他们整合到一个视图中

有不少基于类的预建视图在Horizon。咱们试着提供起始点给全部的通用整合组件。

这种状况下咱们想要一个起始的视图类型与tab和tables一块儿工做,那应该是TabbedTableView类,它很好的动态延时加载能力tab组提供并且混合在actions中,同时AJAX更新tables在用户端没有作任何工做。让咱们看看代码应该是什么样子:

from .tables import FlockingInstancesTable
from .tabs import FlockingTabs

class IndexView(tabs.TabbedTableView):
    tab_group_class = FlockingTabs
    table_class = FlockingInstanceTable
    template_name = 'visualizations/flocking/index.html'
这提供了咱们100%的方法给咱们想要的,若是这个特殊的例子不包含一个额外的AJAX调用来回收咱们的可视化数据经过AJAX。所以咱们须要重写类中的get方法来返回一个正确的数据给一个AJAX调用:


from .tables import FlockingInstancesTable
from .tabs import FlockingTabs

class IndexView(tabs.TabbedTableView):
    tab_group_class = FlockingTabs
    table_class = FlockingInstanceTable
    template_name = 'visualizations/flocking/index.html'

    def get(self, request, *args, **kwargs):
        if self.request.is_ajax() and self.request.GET.get("json", False):
            try:
                instances = utils.get_instances_data(self.request)
            except:
                instances = []
                exceptions.handle(request, _('Unable to retrieve instance list.'))
            data = json.dumps([i._apiresource._info for i in instances])
            return http.HttpResponse(data)
        else:
            return super(IndexView, self).get(request, *args, **kwargs)
在这个例子中,咱们重写了get()方法这样若是不是一个AJAX请求可是有 咱们寻找的GET参数,返回咱们的实例数据用JSON格式;不然只是像日常同样返回视图功能。


模板

这里咱们须要三个模板:一个给视图,一个给咱们的每一个两个tabs。视图模板能够继承其余的dashboard:

{% extends 'syspanel/base.html' %}
{% load il8n %}
{% block title %}{% trans "Flocking" %}{% endblock %}

{% block page_header %}
   {% include "horizon/common/_page_header.html" with title=_("Flocking") %}
{% endblock page_header %}

{% block syspanel_main %}
<div class="row-fluid">
 <div class="span12">
   {{ tab_group.render }}
 </div>
</div>
{% endblock %}
这给了咱们一个自定义的页面标题,一个头,和渲染视图提供的tab组、


对于tabs,使用的table是重用的模板,"horizon/common/_detail_table.html"。这适合任何的只显示一个table的tab。

第二个tab是一个隐藏的,可是它很是简单并且能够在github的例子中研究它。

每一个tab须要一个模板与它关联。

经过这些本地的代码,惟一的剩下的事情就是去整合它们到咱们的 OpenStack Dashboard网站。

创建一个项目

大部分的人会依靠Horizon定制本身的Dashboard。因此,这个教程只是想说明它能够被定制。

结构

一个基于Horizon的网站形式是一个典型的Django项目:

site/
  |--__init__.py
  |--manage.py
  |--demo_dashboard/
     |--__init__.py
     |--models.py  # required for Django even if unused
     |--settings.py
     |--templates/
     |--static/
demo_dashboard在咱们的python路径下,settings.py文件将包含咱们的定制的Horizon配置。


配置文件

有一些关键的事情你须要定制化你网站的配置文件:指定定制的dashboard和panels,获取你的客户端的异常类,和指定一个高级覆写文件。

指定dashboards

最基础的事情是添加你本身的定制的dashboard使用HORIZON_CONFIG字典在配置文件中:

HORIZON_CONFIG = {
    'dashboards': ('nova', 'syspanel', 'visualizations', 'settings',),
}
在这种状况下,咱们使用了默认的Horizon配置而后添加了咱们的visualizations dashboard。注意这里的名字就是pyhton路径下dashboard的模块的名字。它会找到咱们的dashboard.py文件在里面,而后自动从这加载dashboard和它的panesl。

错误处理

添加定制的错误处理给你的API客户端很是的简单。在这个例子中不是必须的。经过定制'exceptions'的值在HORIZON_CONFIG字典:


import my_api.exceptions as my_api

'exceptions': {'recoverable': [my_api.Error,
                               my_api.ClientConnectionError],
               'not_found': [my_api.NotFound],
               'unauthorized': [my_api.NotAuthorized]}

重写文件

重写文件是"god-mode"dashboard编辑。经过一个重写文件你能够修改任何你想存在在代码中的行为。这个教程并不深刻,可是咱们只能说能力越大责任越大。

为了指定一个重写文件,你设置customization_module''值在HORIZON_CONFIG字典。

HORIZON_CONFIG = {
    'customization_module': 'demo_dashboard.overrides'
}
这个文件可以添加dashboard,添加panel到存在的dashboard,重命名存在的dashboards和panels(或者改变他们的属性),从存在的dashboard上删除panels,等等。

咱们能够说的跟多,可是只会更加危险 ....

结论

教程中的信息从不意味着给你一个能够工做的dashboard,由于这里涉及太多的javascript在可视化,这和Horizon自己是不相干的。

若是你想看到最终的产品,查找github例子。

clone repository 而后执行./run_tests.sh --runserver.这会给你一个能够工做的dashboard使用了每个教程中的技巧。

相关文章
相关标签/搜索