自制Openerp图表

自制Openerp图表注意 1 本文介绍一种简单的 非通用的改进 openerp 的思路 并非一定要取代原有方式 2 本文会修改 web graph 模块 如果在你的项目里使用了这个模块 请避免修改 以防止异常 3 本文基于 openerp6 1 通过本文 你可以知道 1 web graph 的运行机制 2 如何动手修改这个模块 看看这个模块的结构 客户端采用的是 highcha

注意:

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

看看这个模块的结构:
自制Openerp图表

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

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

修改__openerp__.py

{
    "name": "Graph Views",
    "category" : "Hidden",
    "description":"""Graph Views for Web Client

* Parse a 
                   
  
                   
                   
                   
                   
                   
                     view but allows changing dynamically the presentation * Graph Types: pie, lines, areas, bars, radar * Stacked / Not Stacked for areas and bars * Legends: top, inside (top/left), hidden * Features: download as PNG or CSV, browse data grid, switch orientation * Unlimited "Group By" levels (not stacked), two cross level analysis (stacked) """, "version": "3.0", "depends": ['web'], "js": [ "static/lib/highchart/js/highcharts.js", "static/src/js/graph.js" ], "css": [ "static/src/css/*.css", ], 'qweb' : [ "static/src/xml/*.xml", ], "auto_install": True } 
                   

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




$(function () {
    var chart;
    $(document).ready(function() {
        chart = new Highcharts.Chart({
            chart: {
                renderTo: 'container',
                type: 'line',
                marginRight: 130,
                marginBottom: 25
            },
            title: {
                text: 'Monthly Average Temperature',
                x: -20 //center
            },
            subtitle: {
                text: 'Source: WorldClimate.com',
                x: -20
            },
            xAxis: {
                categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                    'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
            },
            yAxis: {
                title: {
                    text: 'Temperature (°C)'
                },
                plotLines: [{
                    value: 0,
                    width: 1,
                    color: '#808080'
                }]
            },
            tooltip: {
                formatter: function() {
                        return ''+ this.series.name +'
'+ this.x +': '+ this.y +'°C'; } }, legend: { layout: 'vertical', align: 'right', verticalAlign: 'top', x: -10, y: 100, borderWidth: 0 }, series: [{ name: 'Tokyo', 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] }, { name: 'New York', 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] }, { name: 'Berlin', 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] }, { name: 'London', 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] }] }); }); });

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











# -*- coding: utf-8 -*-

import tools
from tools import safe_eval

try:
    # embedded
    import openerp.addons.web.common.http as openerpweb
    from openerp.addons.web.controllers.main import View
except ImportError:
    # standalone
    import web.common.http as openerpweb
    from web.controllers.main import View

from lxml import etree

class GraphView(View):
    _cp_path = '/web_graph/graph'
    
    @tools.cache(timeout=3600)
    def from_db(self, obj, chart_type, title, fields, domain, group_by, context):
        result = {}
        if len(fields)<2:
            return result
        
        field_x = fields[1]
        field_y = fields[2]
        field_z = (len(fields)==4) and fields[3] or ''

        ids = obj.search(domain)
            
        if ids:
            records = obj.read(ids)
            
            #field_x
            categories = []
            #field_z
            groups = []
            series = []
            
            if field_z:
                data_set = {}
                for r in records:
                    #get categories.
                    if r[field_x] not in categories:
                        categories.append(r[field_x])
                        
                    if r[field_z] not in groups:
                        groups.append(r[field_z])
                    
                    data_set[r[field_x]+r[field_z]] = r[field_y]
                
                #transform data
                # series

                for g in groups:
                    s = {'name':g, 'data':[]}
                    for cate in categories:
                        s['data'].append(data_set.get(cate+g, 0))
                    series.append(s)

            else:
                data = []
                for r in records:
                    if r[field_x] not in categories:
                        categories.append(r[field_x])
                    data.append(r[field_y])
                
                series.append({'data':data})

        return categories, series
    
    @openerpweb.jsonrequest
    def data_get(self, req, model=None, domain=[], group_by=[], view_id=False, context={}, kwargs):

        obj = req.session.model(model)
        xml = obj.fields_view_get(view_id, 'graph')
        graph_xml = etree.fromstring(xml['arch'])
        
        chart_type = graph_xml.attrib.get('type') or 'line'
        chart_title = graph_xml.attrib.get('string') or '图表'
        fields = [ element.attrib.get('name') for element in graph_xml.iter() ]
        
        data = self.from_db(obj, chart_type, chart_title, fields, domain, group_by, context)

        result = {
            'title':chart_title,
            'categories':data[0],
            'series':data[1],
            'chart_type':chart_type,
        }
        
        return result


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


                         
  
                         
                         
                         
                         
                          
                           
                          
                            sale.order.report.monthly.tree 
                           
                          
                            sale.order.report.monthly 
                           
                          
                            tree 
                           
                           
                            
                             
                             
                             
                            
                           
                         

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

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


                                
  
                                
                                
                                
                                
                                


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

/*---------------------------------------------------------
 * OpenERP web_graph
 *---------------------------------------------------------*/

openerp.web_graph = function (openerp) {

var QWeb = openerp.web.qweb,
     _lt = openerp.web._lt;
openerp.web.views.add('graph', 'openerp.web_graph.GraphView');
openerp.web_graph.GraphView = openerp.web.View.extend({
    display_name: _lt('Graph'),
    
    init: function(parent, dataset, view_id, options) {
        this._super(parent);
        this.dataset = dataset;
        this.view_id = view_id;
        this.set_default_options(options);
        this.fields_view = {};
        
        this.model = dataset.model;
        this.chart_id = Math.floor((Math.random()*100)+1);
    },
    
    start: function() {
        this._super();
        
        this.$element.html(QWeb.render("GraphView", {
            "chart_id": this.chart_id,
            'element_id': this.widget_parent.element_id
        }));
    },
    stop: function() {
        this._super();
    },

    /*
     * get data here.
    */
    do_search: function(domain, context, group_by) {
        
        this.rpc(
                   '/web_graph/graph/data_get',
                   {
                       'model': this.model,
                       'domain': domain,
                       'group_by': group_by,
                       'view_id': this.view_id,
                       'context': context
                   }, this.on_search
                );

    },
    
    on_search: function(result){
        container = this.widget_parent.element_id+"-chart-"+this.chart_id;
        
        var chart = new Highcharts.Chart({
            chart: {
                renderTo: container,
                height: 300
            },
            title: {
                text: result.title
            },
            xAxis: {
                categories: result.categories
            },
            series: result.series
        });
    },
    
    do_show: function() {
        this.do_push_state({});
        return this._super();
    }
});
};
// vim:et fdc=0 fdl=0:

能看出,主要是三个方法(标准的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.

自制Openerp图表


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



原文:http://blog.csdn.net/d_yang/article/details/7931719












































































































版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/229326.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午4:57
下一篇 2026年3月16日 下午4:57


相关推荐

  • inetaddress java_java中Inetaddress类

    inetaddress java_java中Inetaddress类InetAddress类InetAddress类用来封装我们前面讨论的数字式的IP地址和该地址的域名。你通过一个IP主机名与这个类发生作用,IP主机名比它的IP地址用起来更简便更容易理解。InetAddress类内部隐藏了地址数字。InetAddress类中的工厂方法InetAddress类没有明显的构造函数。为生成一个InetAddress对象,必须运用一个可用的工厂方法。工厂方法(factor…

    2022年6月23日
    21
  • Hunyuan-MT-7B-WEBUI实战教程:快速部署33语种翻译服务

    Hunyuan-MT-7B-WEBUI实战教程:快速部署33语种翻译服务

    2026年3月12日
    2
  • 面面俱到的Java接口自动化测试实战_如何利用TestNG做接口自动化测试?Java+TestNG测试实例分享…

    面面俱到的Java接口自动化测试实战_如何利用TestNG做接口自动化测试?Java+TestNG测试实例分享…上一篇自动化测试我们大概了解了测试的目标 测试的技术选型以及搭建平台的目标及需求 也确定了自动化测试方案以 testNg 作为整个测试流程贯穿的基础支持框架 那么 testNg 究竟有什么特点 本篇开始我们来详细的学习 testNg 这个测试框架 为什么要用 testNg 首先我们学习之前 先思考一个问题 java 测试的框架很多 为什么要用 testNg 呢 比如 junit 使用的人很多 几乎所有 java 开发人员都

    2026年3月17日
    2
  • iocp详解_iocp是异步io吗

    iocp详解_iocp是异步io吗#include”SOCKET.h”#includeDWORDWINAPIThreadProc(LPVOIDpvParam);#definePORT8080#defineLISTEN_QUEUE200//AcceptEx和GetAcceptExSockaddrs的函数指针,用于调用这两个扩展函数LPFN_ACCEPTEX       

    2026年4月17日
    4
  • 同济大学老师邮箱汇总

    同济大学老师邮箱汇总本文所列老师邮箱都是同济大学邮箱。姓名:殷俊锋学院:数学科学学院(计算数学)职称:教授邮箱:yinjf@tongji.edu.cn姓名:杨筱菡学院:数学科学学院(概率与统计)职称:副教授

    2022年7月3日
    75
  • ubuntu java 卸载_ubuntu 怎么卸载java「建议收藏」

    ubuntu java 卸载_ubuntu 怎么卸载java「建议收藏」很简单。许多人比较厌恶Java,但是很有可能因为某些原因你需要安装Java,尽管你很讨厌它。在这篇文章中,我们将展示如何在Ubuntu14.04安装Java(也可能在LinuxMint17同样适用)。JREvsOpenJDKvsOracleJDK在我们继续了解如何安装Java之前,让我们快速地了解JRE、OpenJDK和OracleJDK之间的不同之处。JRE(JavaRunt…

    2022年5月12日
    54

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号