感谢朋友支持本博客,欢迎共同探讨交流。因为能力和时间有限,错误之处在所难免,欢迎指正!

如有转载。请保留源作者博客信息。

Better Me的博客blog.csdn.net/tantexian

如需交流,欢迎大家博客留言。

1、鉴于国内java开发者比較多。java web方面的技术比較成熟。所以用python
django(openstack)框架和java的strurs做个类比,让大家可以更直观的理解、更快的进入到开发中:


附图大致对照下,详细细节,自行查找相关资料:


2、接下来正式開始解说。怎样在openstack中使用自己定义插件,本文以Jquery zTree树形插件为例。
第一步封装url地址。请求数据,在urls中自己定义url:
为了方便兴许大家复制代码,也顺带附上源码
urlpatterns = patterns('',
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?

P<tenant_id>[^/]+)/update/$',views.UpdateIsolationView.as_view(), name='update'),

    url(r'^(?P<tenant_id>[^/]+)/tree/$',views.TreeView.as_view(), name='tree'),
    url(r'^(?P<tenant_id>[^/]+)/get_tree_data/$',views.JSONGetView.as_view(), name='get_tree_data'),
    url(r'^(?P<tenant_id>[^/]+)/set_tree$',views.JSONSetView.as_view(), name='set_tree'),
)


3、依据url规则匹配到相应的views的JSONGetView类:

from django.views import generic
from django.http import HttpResponse # noqa
import json
class JSONGetView(generic.View):
    def get(self, request, *args, **kwargs): #定义get方法
        tenant_id = self.kwargs["tenant_id"] #从url中截取參数值tenant_id
        aggregates = []
        try:
            aggregates = api.nova.aggregate_details_list(self.request)
            api.nova.isolatation_tree_list(self.request, tenant_id)
        except Exception:
            exceptions.handle(request,
                              _('Unable to retrieve host aggregates list.'))
        aggregates.sort(key=lambda aggregate: aggregate.name.lower())
#调用底层api 构造 zTree的数据
        tree_list = []
        for ag in aggregates:
            tree_data = {}
            tree_data['id'] = ag.availability_zone
            tree_data['name'] = ag.availability_zone
            tree_data['pId'] = 'NULL'
            tree_data['open'] = 'true'
            if tree_data not in tree_list:
                tree_list.append(tree_data)
            tree_data = {}
            tree_data['id'] = ag.name
            tree_data['name'] = ag.name
            tree_data['pId'] = ag.availability_zone
            tree_data['open'] = 'true'
            if tree_data not in tree_list:
                tree_list.append(tree_data)
            for hostname in ag.hosts:
                tree_data = {}
                tree_data['id'] = hostname
                tree_data['name'] = hostname
                tree_data['pId'] = ag.name
                tree_data['open'] = 'true'
                if tree_data not in tree_list:
                    tree_list.append(tree_data)
        result = json.dumps(tree_list) #此处将python对象转换成json对象
        print (result)
        return HttpResponse(result,content_type="application/json")

4、到此获取数据的url完毕,測试下url(浏览器直接訪问):
得到数据:
[{
 "open": "true",
 "pId": "NULL",
 "id": "zone1",
 "name": "zone1"
},
{
 "open": "true",
 "pId": "zone1",
 "id": "ag1",
 "name": "ag1"
},
{
 "open": "true",
 "pId": "ag1",
 "id": "node32",
 "name": "node32"
},
{
 "open": "true",
 "pId": "ag1",
 "id": "node31",
 "name": "node31"
},
{
 "open": "true",
 "pId": "zone1",
 "id": "ag2",
 "name": "ag2"
},
{
 "open": "true",
 "pId": "ag2",
 "id": "node33",
 "name": "node33"
},
{
 "open": "true",
 "pId": "NULL",
 "id": "zone2",
 "name": "zone2"
},
{
 "open": "true",
 "pId": "zone2",
 "id": "ag3",
 "name": "ag3"
},
{
 "open": "true",
 "pId": "ag3",
 "id": "node35",
 "name": "node35"
},
{
 "open": "true",
 "pId": "ag3",
 "id": "node34",
 "name": "node34"
}]
url能正确获取数据。測试通过。


5、用ajax在html页面中请求该url获取数据:
先附上页面模板代码:

当中javascript要写在标签{% block modal-body %}中才干失效。详细的zTree的js导入本文使用了为压缩的方式。直接导入。



{# add by ttx 2014-9-25#}
  <link rel="stylesheet" href="{{ STATIC_URL }}dashboard/js/zTree/css/demo.css" type="text/css">
 <link rel="stylesheet" href="{{ STATIC_URL }}dashboard/js/zTree/css/zTreeStyle/zTreeStyle.css" type="text/css">
 <script type="text/javascript" src="{{ STATIC_URL }}dashboard/js/zTree/js/jquery.ztree.core-3.5.js"></script>
 <script type="text/javascript" src="{{ STATIC_URL }}dashboard/js/zTree/js/jquery.ztree.excheck-3.5.js"></script>
zTree插件路径:

具体解释ajax请求:
var url = '/dashboard/admin/isolations/{{ tenant_id }}/get_tree_data'; #此处为ajax的url地址,与步骤4中浏览器訪问一致
 $.ajax({ #当中$代表Jquery插件,ajax为Jquery插件的方法
             type: "get", #type主要有get、post。当中get用于获取数据。是幂等操作、post用于跟新数据
             async: false, #false代码同步刷新,true代表异步刷新。本演示样例须要等到数据返回再进行tree的渲染,因此须要同步
             url: url, #请求的url地址
             dataType: "json", #数据返回类型为json
              success: function (data) { #ajax请求成功之后得到数据data。运行success:后面function里面代码
                           json = JSON.stringify(data);
                           host_tree_data = JSON.parse(json)
                }
});
很多其它ajax具体使用解说请自行參考相关资料。

兴许就是具体的zTree依据得到的数据host_tree_data 。生成zone、aggregate、host的节点树。附上简单代码。不具体解释:
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% load url from future %}
{% block form_id %}create_image_form{% endblock %}
{% block form_action %}{% url 'horizon:admin:images:create' %}{% endblock %}
{% block form_attrs %}enctype="multipart/form-data"{% endblock %}
{% block modal-header %}{% trans "Isolatation tree" %}{% endblock %}
{% block modal-body %}
 <SCRIPT type="text/javascript">
  <!--
  var setting = {
   view: {
    selectedMulti: false
   },
   check: {
    enable: true
   },
   data: {
    simpleData: {
     enable: true
    }
   },
   callback: {
    beforeCheck: beforeCheck,
    onCheck: onCheck
   }
  };
  var code, log, className = "dark";
  function beforeCheck(treeId, treeNode) {
   className = (className === "dark" ?

"":"dark");

   showLog("[ "+getTime()+" beforeCheck ]&nbsp;&nbsp;&nbsp;&nbsp;" + treeNode.name );
   return (treeNode.doCheck !== false);
  }
  function onCheck(e, treeId, treeNode) {
   showLog("[ "+getTime()+" onCheck ]&nbsp;&nbsp;&nbsp;&nbsp;" + treeNode.name );
            getAllChangeNodes()
  }
        function getAllChangeNodes() {
   var treeObj = $.fn.zTree.getZTreeObj("treeDemo");
            var nodes = treeObj.getChangeCheckedNodes();
            $('#mytest').html(JSON.stringify(nodes));
            var url = '/dashboard/admin/isolations/{{ tenant_id }}/set_tree';
            var data={};
            data["jsonTree"] = JSON.stringify(nodes);
            jQuery.ajax({
                type:"POST",
                url : url,
                data:data,
                dataType : "json",
                beforeSend: function(xhr, settings){
                      var csrftoken = $.cookie('csrftoken');
                      xhr.setRequestHeader("X-CSRFToken", csrftoken);
                  },
                success : function(data) {
                }
            });
  }
  function showLog(str) {
   if (!log) log = $("#log");
   log.append("<li class='"+className+"'>"+str+"</li>");
   if(log.children("li").length > 6) {
    log.get(0).removeChild(log.children("li")[0]);
   }
  }
  function getTime() {
   var now= new Date(),
   h=now.getHours(),
   m=now.getMinutes(),
   s=now.getSeconds(),
   ms=now.getMilliseconds();
   return (h+":"+m+":"+s+ " " +ms);
  }
  function checkNode(e) {
   var zTree = $.fn.zTree.getZTreeObj("treeDemo"),
   type = e.data.type,
   nodes = zTree.getSelectedNodes();
   if (type.indexOf("All")<0 && nodes.length == 0) {
    alert("请先选择一个节点");
   }
   if (type == "checkAllTrue") {
    zTree.checkAllNodes(true);
   } else if (type == "checkAllFalse") {
    zTree.checkAllNodes(false);
   } else {
    var callbackFlag = $("#callbackTrigger").attr("checked");
    for (var i=0, l=nodes.length; i<l; i++) {
     if (type == "checkTrue") {
      zTree.checkNode(nodes[i], true, false, callbackFlag);
     } else if (type == "checkFalse") {
      zTree.checkNode(nodes[i], false, false, callbackFlag);
     } else if (type == "toggle") {
      zTree.checkNode(nodes[i], null, false, callbackFlag);
     }else if (type == "checkTruePS") {
      zTree.checkNode(nodes[i], true, true, callbackFlag);
     } else if (type == "checkFalsePS") {
      zTree.checkNode(nodes[i], false, true, callbackFlag);
     } else if (type == "togglePS") {
      zTree.checkNode(nodes[i], null, true, callbackFlag);
     }
    }
   }
  }
  function setAutoTrigger(e) {
   var zTree = $.fn.zTree.getZTreeObj("treeDemo");
   zTree.setting.check.autoCheckTrigger = $("#autoCallbackTrigger").attr("checked");
   $("#autoCheckTriggerValue").html(zTree.setting.check.autoCheckTrigger ? "true" : "false");
  }
  $(document).ready(function(){
            var url = '/dashboard/admin/isolations/{{ tenant_id }}/get_tree_data';
            $.ajax({
                       type: "get",
                       async: false,
                       url: url,
                       dataType: "json",
                       success: function (data) {
                           json = JSON.stringify(data);
                           host_tree_data = JSON.parse(json)
                       }
                   });
            var zNodes =[
                            { id:1, pId:0, name:"1", open:true},
                            { id:11, pId:1, name:"1-1"},
                            { id:12, pId:1, name:"1-2"},
                            { id:111, pId:11, name:"1-1-1","checked":"true"},
                            { id:112, pId:11, name:"1-1-2"},
                        ];
   $.fn.zTree.init($("#treeDemo"), setting, host_tree_data);
   $("#checkTrue").bind("click", {type:"checkTrue"}, checkNode);
   $("#checkFalse").bind("click", {type:"checkFalse"}, checkNode);
   $("#toggle").bind("click", {type:"toggle"}, checkNode);
   $("#checkTruePS").bind("click", {type:"checkTruePS"}, checkNode);
   $("#checkFalsePS").bind("click", {type:"checkFalsePS"}, checkNode);
   $("#togglePS").bind("click", {type:"togglePS"}, checkNode);
   $("#checkAllTrue").bind("click", {type:"checkAllTrue"}, checkNode);
   $("#checkAllFalse").bind("click", {type:"checkAllFalse"}, checkNode);
   $("#autoCallbackTrigger").bind("change", {}, setAutoTrigger);
  });
  //-->
 </SCRIPT>
<h1>用 zTree 方法 勾选 checkbox</h1>
<h6>[ 文件路径: excheck/checkbox_fun.html ]</h6>
<div class="content_wrap">
 <div class="zTreeDemoBackground left">
  <ul id="treeDemo" class="ztree"></ul>
 </div>
</div>
 <div>
  <ul class="info">
            <div id="mytest">11111111111111111111111111111111111111111111</div>
   <li class="title"><h2>1、beforeCheck / onCheck 事件回调函数控制</h2>
    <ul class="list">
    <li>利用 beforeCheck / onCheck 事件回调函数 能够控制是否同意 更改 节点勾选状态,这里简单演示怎样监控此事件</li>
    <li><p>这里还演示了 checkNode / checkAllNodes 方法触发 beforeCheck / onCheck 事件回调函数的情况。试试看:<br/>
     &nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" id="autoCallbackTrigger" /> setting.check.autoCheckTrigger: <span id="autoCheckTriggerValue">false</span><br/>
     &nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" id="callbackTrigger" checked /> 运行勾选方法是否触发 callback <br/>
     &nbsp;&nbsp;&nbsp;&nbsp;单节点--[ <a id="checkTrue" href="#" title="不想勾选我就不勾选你..." onclick="return false;">勾选</a> ]
     &nbsp;&nbsp;&nbsp;&nbsp;[ <a id="checkFalse" href="#" title="不想取消勾选我就不取消你..." onclick="return false;">取消勾选</a> ]
     &nbsp;&nbsp;&nbsp;&nbsp;[ <a id="toggle" href="#" title="你想如何?..." onclick="return false;">勾选 切换</a> ]<br/>
     &nbsp;&nbsp;&nbsp;&nbsp;单节点 ( 影响父子 )--[ <a id="checkTruePS" href="#" title="不想勾选我就不勾选你..." onclick="return false;">勾选</a> ]
     &nbsp;&nbsp;&nbsp;&nbsp;[ <a id="checkFalsePS" href="#" title="不想取消勾选我就不取消你..." onclick="return false;">取消勾选</a> ]
     &nbsp;&nbsp;&nbsp;&nbsp;[ <a id="togglePS" href="#" title="你想如何?..." onclick="return false;">勾选 切换</a> ]<br/>
     &nbsp;&nbsp;&nbsp;&nbsp;所有节点--[ <a id="checkAllTrue" href="#" title="无论你有多NB,统统都要听我的!

" onclick="return false;">勾选</a> ]

     &nbsp;&nbsp;&nbsp;&nbsp;[ <a id="checkAllFalse" href="#" title="无论你有多NB,统统都要听我的!

" onclick="return false;">取消勾选</a> ]</p>

    </li>
    <li><p><span class="highlight_red">使用 zTreeObj.checkNode / checkAllNodes 方法,具体请參见 API 文档中的相关内容</span><br/>
     beforeCheck / onCheck log:<br/>
     <ul id="log" class="log" style="height:130px;"></ul></p>
    </li>
    </ul>
   </li>
   <li class="title"><h2>2、setting 配置信息说明</h2>
    <ul class="list">
    <li>同 "checkbox 勾选操作" 中的说明</li>
    </ul>
   </li>
   <li class="title"><h2>3、treeNode 节点数据说明</h2>
    <ul class="list">
    <li>同 "checkbox 勾选操作" 中的说明</li>
    </ul>
   </li>
  </ul>
 </div>
{% endblock %}
{% block modal-footer %}
  <input class="btn btn-primary pull-right" type="submit" value="{% trans "Save" %}" />
  <a href="{% url 'horizon:admin:images:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
{% endblock %}
跟多zTree使用,请自行參考zTree官网:www.ztree.me/

页面终于展示:

此处的zTree页面比較丑。能够改动css样式,调整,附上bootstrap风格的树形插件样式。http://www.js-css.cn/jscode/nav/nav23/


到此通过ajax获取数据到页面展示解说完成。

6、讲完ajax从后台获取数据到前台接下来解说,怎样通过ajax,把页面的数据传递给后台处理:
附上代码:
function getAllChangeNodes() {
   var treeObj = $.fn.zTree.getZTreeObj("treeDemo");
            var nodes = treeObj.getChangeCheckedNodes();
            $('#mytest').html(JSON.stringify(nodes)); #JSON.stringify(nodes)将js对象nodes,转化为json对象
            var url = '/dashboard/admin/isolations/{{ tenant_id }}/set_tree';
            var data={}; #url中传递的数据,相当于$url?

jsonTree=JSON.stringify(nodes)

            data["jsonTree"] = JSON.stringify(nodes);
            jQuery.ajax({
                type:"POST", #ajax类型。post进来进行更新
                url : url,
                data:data,
                dataType : "json",
                beforeSend: function(xhr, settings){ #此处的beforeSend用来解决ajax在django中报csrftoken错误
                      var csrftoken = $.cookie('csrftoken');
                      xhr.setRequestHeader("X-CSRFToken", csrftoken);
                  },
                success : function(data) { #ajax请求成功之后运行
                }
            });
  }

依据上述url = '/dashboard/admin/isolations/{{ tenant_id }}/set_tree';到urls.py中找相应匹配的url:
urlpatterns = patterns('',
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<tenant_id>[^/]+)/update/$',views.UpdateIsolationView.as_view(), name='update'),
    url(r'^(?

P<tenant_id>[^/]+)/tree/$',views.TreeView.as_view(), name='tree'),

    url(r'^(?P<tenant_id>[^/]+)/get_tree_data/$',views.JSONGetView.as_view(), name='get_tree_data'),
    url(r'^(?P<tenant_id>[^/]+)/set_tree$',views.JSONSetView.as_view(), name='set_tree'),
)



依据url匹配规则,跟进到JSONSetView:
class JSONSetView(generic.View):
    def post(self, request, *args, **kwargs): #由于ajax的请求类型为post因此实现post函数,否则会报错
        tenant_id = self.kwargs["tenant_id"] #从URL中获取tenant_id
        json_tree = request.POST.get("jsonTree") #从ajax发过来的请求中获取jsonTree
json数据
        tree_change_nodes = json.loads(json_tree) #将页面传递的json数据,转换为python对象。详细转换规则自行參考
#此处依据前端传送的数据,调用api传递给后端处理
        api.nova.isolatation_add_tree(request, tenant_id, tree_change_nodes) 
        return HttpResponse(tree_change_nodes,content_type="application/json")

解说完成!

openstack页面自己定义插件使用具体解释(django、ajax、post)(zTree为例)的更多相关文章

  1. jQuery上定义插件并重设插件构造函数

    插件alert的全部代码,每个插件都定义在如下类似的作用域中: +function ($) { 'use strict'; // ALERT CLASS DEFINITION // ========= ...

  2. js自己定义插件-选项卡

    该功能比較简单.巩固一下jquery插件写法,注意引入的jquery.js  . 自己定义插件路径代码例如以下: 页面: <!doctype html> <html> < ...

  3. 查看SQLSERVER内部数据页面的小插件Internals Viewer

    原文:查看SQLSERVER内部数据页面的小插件Internals Viewer 查看SQLSERVER内部数据页面的小插件Internals Viewer 感觉internals viewer这个名 ...

  4. phonegap(cordova) 自己定义插件代码篇(五)----android ,iOS 集成微信登陆

    统一登陆还是非常有必要的,安全,放心.代码 /*cordov 微信自己定义插件*/ (function (cordova) { var define = cordova.define; define( ...

  5. Android Cordova 插件开发之编写自己定义插件

    前言 本文适合Android+web的复合型人才,由于cordova本身就是混合开发,所以在Android开发的基础上,还要懂web相关技术(HTML+CSS+JS).可是也有例外,比方我.仅仅需负责 ...

  6. Gradle自己定义插件

    Gradle自己定义插件 在Gradle中创建自己定义插件,Gradle提供了三种方式: 在build.gradle脚本中直接使用 在buildSrc中使用 在独立Module中使用 开发Gradle ...

  7. jQuery 选择器 筛选器 样式操作 文本操作 属性操作 文档处理 事件 动画效果 插件 each、data、Ajax

    jQuery jQuery介绍 1.jQuery是一个轻量级的.兼容多浏览器的JavaScript库. 2.jQuery使用户能够更方便地处理HTML Document.Events.实现动画效果.方 ...

  8. jQuery的插件和跨域、ajax

    1. 插件: 也称组件 什么是: 拥有专属的HTML,CSS和js的独立页面区域 为什么: 重用! 何时: 只要一个功能/区域可能被反复使用时 如何: 3个来源: 1. 官方插件:jquery ui ...

  9. 页面注册系统--使用forms表单结合ajax

    页面注册系统--使用forms表单结合ajax 在Django中通过forms构建一个表单 1.urls.py 配置路由 from django.conf.urls import url from d ...

随机推荐

  1. 怎样在nexus 中 搜索到远程maven仓库中的jar 文件

    怎样在nexus 中 搜索到远程maven仓库中的jar 文件 url: http://www.oschina.net/question/95712_21999 点击Administration菜单下 ...

  2. 使用WinPcap编程

    创建一个使用 wpcap.dll 的应用程序 用 Microsoft Visual C++ 创建一个使用 wpcap.dll 的应用程序,需要按一下步骤: 在每一个使用了库的源程序中,将 pcap.h ...

  3. caffe实现自己的层

    http://blog.csdn.net/xizero00/article/details/52529341 将这篇博客所讲进行了实现 1.LayerParameter也在caffe.proto文件中 ...

  4. error while loading shared libraries: libclntsh.so.11.1

    解决这个问题有两种方法 1.在当前用户下,添加链接库所在路径 LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH; export LD_LIBRARY_ ...

  5. C++获取本机用于连接的IP地址

    最近写个程序需要获取本机用于连接的IP地址,经过很多的尝试后,最终使用的方法如下: 使用cmd命令    netstat  | findstr “192.168.6.66:3333” > D:\ ...

  6. 零基础入门学习Python(31)--永久存储:腌制一缸美味的泡菜

    知识点 pickle( 泡菜 ) 模块介绍: pickle模块作用是持久化的储存数据. 在Python程序运行中得到了一些字符串.列表.字典等数据,想要长久的保存下来,方便以后使用, 而不是简单的放入 ...

  7. docker配置国内加速器

    一.登录到daocloud网站后选择如下地址的加速器 二.根据配置提示在linux上执行对应的配置命令: curl -sSL https://get.daocloud.io/daotools/set_ ...

  8. C++ 类 直接定义对象与new对象的区别

    new创建类对象与直接定义的区别 new创建对象的特点 new创建类对象需要指针接收,一处初始化,多处使用 new创建类对象使用完需delete销毁 new创建对象直接使用堆空间,而局部不用new定义 ...

  9. Vue如何mock数据模拟Ajax请求

    我们在做一个项目时前期可能没有后端提供接口模拟数据,那么作为前端就需要自己写json文件模拟数据加载.网上往往参考的都是不全面的,比如get请求没问题但是post请求就报错了.在Vue中只需要vue- ...

  10. Jupyter notebook使用笔记

    常用快捷键 For a Cell,   Blue -> selecting. Green -> editing. Esc -> exist edit When the cell is ...