Odoo中文社区可以通过以下两个域名访问:shine-it.net , odoo.net.cn

由于系统升迁的原因,本论坛部分较早期的内容存在格式和链接损坏失效的问题,并非本论坛系统本身的缺陷,望谅解

本社区没有维护任何QQ群讨论组,任何与本社区同名的QQ群讨论组的言论与本社区无关!

开发人员可以登录gitter讨论组: http://gitter.im/odoo-china/Talk, 需要github账号

如果您登录系统碰到问题,请在微信公众号留言:

自制Openerp图表



  • 注意:
    1. 本文介绍一种简单的,非通用的改进openerp的思路。并非一定要取代原有方式。
    2. 本文会修改web_graph模块,如果在你的项目里使用了这个模块,请避免修改,以防止异常。
    3. 本文基于openerp 6.1
    通过本文,你可以知道:
    1. web_graph的运行机制。
    2. 如何动手修改这个模块。

    看看这个模块的结构:
    [attachimg=1]

    客户端采用的是highchart(http://www.highcharts.com/),当然,如果你喜欢其他的lib,都是没问题的。

    第一步,把highcharts给包含到模块来,这样openerp才能把这个库合并输出。
    把highcharts放置在适合的位置。

    修改__openerp__.py

    <br />{<br />&nbsp; &nbsp; &quot;name&quot;: &quot;Graph Views&quot;,<br />&nbsp; &nbsp; &quot;category&quot; : &quot;Hidden&quot;,<br />&nbsp; &nbsp; &quot;description&quot;:&quot;&quot;&quot;Graph Views for Web Client<br /><br />* Parse a &lt;graph&gt; view but allows changing dynamically the presentation<br />* Graph Types: pie, lines, areas, bars, radar<br />* Stacked / Not Stacked for areas and bars<br />* Legends: top, inside (top/left), hidden<br />* Features: download as PNG or CSV, browse data grid, switch orientation<br />* Unlimited &quot;Group By&quot; levels (not stacked), two cross level analysis (stacked)<br />&quot;&quot;&quot;,<br />&nbsp; &nbsp; &quot;version&quot;: &quot;3.0&quot;,<br />&nbsp; &nbsp; &quot;depends&quot;: &#91;&#039;web&#039;],<br />&nbsp; &nbsp; &quot;js&quot;: [<br />&nbsp; &nbsp; &nbsp; &nbsp; &quot;static/lib/highchart/js/highcharts.js&quot;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &quot;static/src/js/graph.js&quot;<br />&nbsp; &nbsp; ],<br />&nbsp; &nbsp; &quot;css&quot;: [<br />&nbsp; &nbsp; &nbsp; &nbsp; &quot;static/src/css/*.css&quot;,<br />&nbsp; &nbsp; ],<br />&nbsp; &nbsp; &#039;qweb&#039; : [<br />&nbsp; &nbsp; &nbsp; &nbsp; &quot;static/src/xml/*.xml&quot;,<br />&nbsp; &nbsp; ],<br />&nbsp; &nbsp; &quot;auto_install&quot;: True<br />}<br /><br />
    




    下面研究highcharts.
    观察highcharts的示例(http://www.highcharts.com/demo/),折线图是这样运行的:

    <br />$(function () {<br />&nbsp; &nbsp; var chart;<br />&nbsp; &nbsp; $(document).ready(function() {<br />&nbsp; &nbsp; &nbsp; &nbsp; chart = new Highcharts.Chart({<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; chart: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; renderTo: &#039;container&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type: &#039;line&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; marginRight: 130,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; marginBottom: 25<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; title: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text: &#039;Monthly Average Temperature&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x: -20 //center<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subtitle: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text: &#039;Source: WorldClimate.com&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x: -20<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; xAxis: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; categories: &#91;&#039;Jan&#039;, &#039;Feb&#039;, &#039;Mar&#039;, &#039;Apr&#039;, &#039;May&#039;, &#039;Jun&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#039;Jul&#039;, &#039;Aug&#039;, &#039;Sep&#039;, &#039;Oct&#039;, &#039;Nov&#039;, &#039;Dec&#039;]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yAxis: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; title: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text: &#039;Temperature (°C)&#039;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; plotLines: [{<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: 0,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; width: 1,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; color: &#039;#808080&#039;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tooltip: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; formatter: function() {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return &#039;&lt;b&gt;&#039;+ this.series.name +&#039;&lt;/b&gt;&lt;br/&gt;&#039;+<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.x +&#039;: &#039;+ this.y +&#039;°C&#039;;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; legend: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; layout: &#039;vertical&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; align: &#039;right&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; verticalAlign: &#039;top&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x: -10,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; y: 100,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; borderWidth: 0<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; series: [{<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: &#039;Tokyo&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: &#039;New York&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: &#039;Berlin&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name: &#039;London&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }]<br />&nbsp; &nbsp; &nbsp; &nbsp; });<br />&nbsp; &nbsp; });<br />&nbsp; &nbsp; <br />});<br />
    




    第二步,研究一下服务端。
    服务端代码集中在graph.py里。
    GraphView类是一个标准的View, 是客户端图表数据的来源,也定义了图表显示方式。如果要修改图表,几乎是要动这个类。
    我们来简单的看。首先修改客户端。
    只要把服务端返回的数据变成这种格式就可以了。动手:

    <br /># -*- coding: utf-8 -*-<br /><br />import tools<br />from tools import safe_eval<br /><br />try:<br />&nbsp; &nbsp; # embedded<br />&nbsp; &nbsp; import openerp.addons.web.common.http as openerpweb<br />&nbsp; &nbsp; from openerp.addons.web.controllers.main import View<br />except ImportError:<br />&nbsp; &nbsp; # standalone<br />&nbsp; &nbsp; import web.common.http as openerpweb<br />&nbsp; &nbsp; from web.controllers.main import View<br /><br />from lxml import etree<br /><br />class GraphView(View):<br />&nbsp; &nbsp; _cp_path = &#039;/web_graph/graph&#039;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; @tools.cache(timeout=3600)<br />&nbsp; &nbsp; def from_db(self, obj, chart_type, title, fields, domain, group_by, context):<br />&nbsp; &nbsp; &nbsp; &nbsp; result = {}<br />&nbsp; &nbsp; &nbsp; &nbsp; if len(fields)&lt;2:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return result<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; field_x = fields[1]<br />&nbsp; &nbsp; &nbsp; &nbsp; field_y = fields[2]<br />&nbsp; &nbsp; &nbsp; &nbsp; field_z = (len(fields)==4) and fields[3] or &#039;&#039;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; ids = obj.search(domain)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; if ids:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; records = obj.read(ids)<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #field_x<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; categories = &#91;]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #field_z<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groups = &#91;]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; series = &#91;]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if field_z:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data_set = {}<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for r in records:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #get categories.<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if r[field_x] not in categories:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; categories.append(r[field_x])<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if r[field_z] not in groups:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groups.append(r[field_z])<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data_set[r[field_x]+r[field_z]] = r[field_y]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #transform data<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # series<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for g in groups:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s = {&#039;name&#039;:g, &#039;data&#039;:&#91;]}<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for cate in categories:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s&#91;&#039;data&#039;].append(data_set.get(cate+g, 0))<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; series.append(s)<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data = &#91;]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for r in records:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if r[field_x] not in categories:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; categories.append(r[field_x])<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data.append(r[field_y])<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; series.append({&#039;data&#039;:data})<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; return categories, series<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; @openerpweb.jsonrequest<br />&nbsp; &nbsp; def data_get(self, req, model=None, domain=&#91;], group_by=&#91;], view_id=False, context={}, **kwargs):<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; obj = req.session.model(model)<br />&nbsp; &nbsp; &nbsp; &nbsp; xml = obj.fields_view_get(view_id, &#039;graph&#039;)<br />&nbsp; &nbsp; &nbsp; &nbsp; graph_xml = etree.fromstring(xml&#91;&#039;arch&#039;])<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; chart_type = graph_xml.attrib.get(&#039;type&#039;) or &#039;line&#039;<br />&nbsp; &nbsp; &nbsp; &nbsp; chart_title = graph_xml.attrib.get(&#039;string&#039;) or &#039;图表&#039;<br />&nbsp; &nbsp; &nbsp; &nbsp; fields = [ element.attrib.get(&#039;name&#039;) for element in graph_xml.iter() ]<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; data = self.from_db(obj, chart_type, chart_title, fields, domain, group_by, context)<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; result = {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#039;title&#039;:chart_title,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#039;categories&#039;:data[0],<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#039;series&#039;:data[1],<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#039;chart_type&#039;:chart_type,<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; return result<br /><br />
    



    很简单, 我只处理这样的Graph定义:

    <br />&lt;record id=&quot;view_sale_order_report_monthly_tree&quot; model=&quot;ir.ui.view&quot;&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &lt;field eval=&quot;1&quot; name=&quot;priority&quot;/&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &lt;field name=&quot;name&quot;&gt;sale.order.report.monthly.tree&lt;/field&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &lt;field name=&quot;model&quot;&gt;sale.order.report.monthly&lt;/field&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &lt;field name=&quot;type&quot;&gt;tree&lt;/field&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &lt;field name=&quot;arch&quot; type=&quot;xml&quot;&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;tree string=&quot;每月销售统计&quot;&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;field name=&quot;date&quot; /&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;field name=&quot;amount&quot; /&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;field name=&quot;source&quot; /&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/tree&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &lt;/field&gt;<br />&nbsp; &nbsp; &lt;/record&gt;<br />
    



    第一个field,作为x轴,第二个,作为y轴。第三个,group成多个系列。 这样的处理就是简单化,并不会考虑openerp原来考虑的事情,所以不是一个通用方法。
    (另,如果要是想进一步扩展graph,则需要修改addons/base/rng/view.rng的规则。)

    下面就是让highcharts显示出来了。
    观察web_graph的xml模板和graph.js
    我记得原来的xml模板element_id上有一些bug(6.1),我修改了一下:

    <br />&lt;template&gt;<br />&nbsp; &nbsp; &lt;div t-name=&quot;GraphView&quot; t-att-id=&quot;element_id+&#039;-chart-&#039;+chart_id&quot;<br />&nbsp; &nbsp; &nbsp; &nbsp;  style=&quot;height:300px;position:relative;&quot;/&gt;<br />&lt;/template&gt;<br />
    



    这是highcharts显示的容器。
    重头戏在graph.js里,这里需要处理很多东西,但是也简单。按照原本的客户端views写法:

    <br /><br />/*---------------------------------------------------------<br /> * OpenERP web_graph<br /> *---------------------------------------------------------*/<br /><br />openerp.web_graph = function (openerp) {<br /><br />var QWeb = openerp.web.qweb,<br />&nbsp; &nbsp;  _lt = openerp.web._lt;<br />openerp.web.views.add(&#039;graph&#039;, &#039;openerp.web_graph.GraphView&#039;);<br />openerp.web_graph.GraphView = openerp.web.View.extend({<br />&nbsp; &nbsp; display_name: _lt(&#039;Graph&#039;),<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; init: function(parent, dataset, view_id, options) {<br />&nbsp; &nbsp; &nbsp; &nbsp; this._super(parent);<br />&nbsp; &nbsp; &nbsp; &nbsp; this.dataset = dataset;<br />&nbsp; &nbsp; &nbsp; &nbsp; this.view_id = view_id;<br />&nbsp; &nbsp; &nbsp; &nbsp; this.set_default_options(options);<br />&nbsp; &nbsp; &nbsp; &nbsp; this.fields_view = {};<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; this.model = dataset.model;<br />&nbsp; &nbsp; &nbsp; &nbsp; this.chart_id = Math.floor((Math.random()*100)+1);<br />&nbsp; &nbsp; },<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; start: function() {<br />&nbsp; &nbsp; &nbsp; &nbsp; this._super();<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; this.$element.html(QWeb.render(&quot;GraphView&quot;, {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;chart_id&quot;: this.chart_id,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#039;element_id&#039;: this.widget_parent.element_id<br />&nbsp; &nbsp; &nbsp; &nbsp; }));<br />&nbsp; &nbsp; },<br />&nbsp; &nbsp; stop: function() {<br />&nbsp; &nbsp; &nbsp; &nbsp; this._super();<br />&nbsp; &nbsp; },<br /><br />&nbsp; &nbsp; /*<br />&nbsp; &nbsp;  * get data here.<br />&nbsp; &nbsp; */<br />&nbsp; &nbsp; do_search: function(domain, context, group_by) {<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; this.rpc(<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  &#039;/web_graph/graph/data_get&#039;,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  &#039;model&#039;: this.model,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  &#039;domain&#039;: domain,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  &#039;group_by&#039;: group_by,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  &#039;view_id&#039;: this.view_id,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  &#039;context&#039;: context<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  }, this.on_search<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; );<br /><br />&nbsp; &nbsp; },<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; on_search: function(result){<br />&nbsp; &nbsp; &nbsp; &nbsp; container = this.widget_parent.element_id+&quot;-chart-&quot;+this.chart_id;<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; var chart = new Highcharts.Chart({<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; chart: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; renderTo: container,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; height: 300<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; title: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; text: result.title<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; xAxis: {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; categories: result.categories<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; series: result.series<br />&nbsp; &nbsp; &nbsp; &nbsp; });<br />&nbsp; &nbsp; },<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; do_show: function() {<br />&nbsp; &nbsp; &nbsp; &nbsp; this.do_push_state({});<br />&nbsp; &nbsp; &nbsp; &nbsp; return this._super();<br />&nbsp; &nbsp; }<br />});<br />};<br />// vim:et fdc=0 fdl=0:<br /><br />
    



    能看出,主要是三个方法(标准的api,参考openerp客户端的文档):
    start, do_search, on_search

    start是指本widget启动的时候要做的事情。
    do_search, 是启动以后,获取数据。
    on_search, 服务端返回数据,根据数据来设置highchart, 显示数据。

    需要注意的是,模板里的element_id( t-att-id="element_id+'-chart-'+chart_id" ) 要和 graph.js里的
    "container = this.widget_parent.element_id+"-chart-"+this.chart_id; " 一致。


    最终,我们得到一个更好看的chart.

    [attachimg=2]


    继续:
    1. 可以写一个更通用的服务端。
    2. 可以扩展这个chart,主要对view.rng里规则的修改。


    心情不好,写的很笼统,如果有疑问,可以回帖,或者新浪微博 @杨振宇_ 
    谨以此文,纪念我远在天堂的儿子。 愿天父的慈爱永远呵护你。



  • 阿门


  • 管理员

    写得很好,一个OpenERP web 开发的最佳实践,
    and 节哀。



  • 阿门



  • 谢谢楼主无私贡献 ~ 拜读之后很受启发!

    现在看到这篇文章,相信您已经度过最艰难的时刻。

    逝者长已矣,来者犹可追。

    默哀并祝福楼主 ~


  • 管理员

    坛子里对OpenERP Web端的技术讨论不多,兄弟的帖子让我们受益匪浅。
    6.1对OpenERP的web client做了完全的重写,变成了OpenERP应用服务器的一个addon了,并且可以象开发服务器端的功能模块一样开发web端的模块: [检测到链接无效,已移除]
    兄弟如果能将其做成一个addon模块,就是一个经典的学习案例了。

    兄弟教会了我什么是坚强,祝福你和你至爱的人。



  • 感谢各位兄弟。

    说说为什么谈论web addon的少。
    要想从技术上搞懂openerp这套体系,不仅仅需要python的基础,还需要很强的javascript的技术。
    这在其他的领域,是那种前台后台通吃的人。
    我恰好都做过一些。所以动手改的话,比较熟悉一些。

    我本人是在一家比较大的制造型企业里,做市场和品牌运作的工作。平时只有在闲的时候才能写一些东西。

    至于各位兄弟说的一个单独的chart addon, 过了这几天,我会考虑单独做一个出来。

    社区里这位“辛巴达”的兄弟: 我帮不了忙,因为我平时的事情太多,是在是不好意思。


Log in to reply