odoo

Packer.Odoo.10---Chapter 6

2017-10-12  本文已影响145人  F4A3

视图层-设计用户界面

这一章节我们会学习用来构建用户界面的视图层。

使用xml文件定义用户界面

用户界面与业务记录一样,都是存储在我们Odoo的数据库中。我们设计用户界面其实本质上就是使用xml文件来把Odoo中的UI从数据库中拉出来显示给用户。
构造一个新的 todo_ui 模块.编辑__mainfest__.py文件:

{
    'name': 'User interface improvements tp the To-Do app',
    'description': 'User friendly features.',
    'author': 'xer',
    'depends': ['todo_user'],
    'data': ['views/todo_view.xml',
             'views/todo_menu.xml',
             'security/ir.model.access.csv',
             ],
}

菜单选项

菜单选项被存贮在ir.ui.menu模型中.可以在** Settings | Technical | User Interface | Menu Items**中查看
我们在'todo_app'应用中已经创建了顶层菜单'To-Do app tasks'.现在来对这个菜单进行扩展
新建views/todo_menu.xml.添加如下代码

     <!--Modify the top menu-->
    <menuitem id="todo_app.menu_todo_task" name="To-Do"></menuitem>
    <!--app menu items-->
    <menuitem id="menu_todo_task_view"
              name="Tasks"
              parent="todo_app.menu_todo_task"
              sequence="10"
              action="todo_app.action_todo_task"/>
    <menuitem id="menu_todo_config"
              name="Configuration"
              parent="todo_app.menu_todo_task"
              sequence="100"
              groups="base.group_system"/>
    <menuitem id="menu_todo_task_stage"
              name="Stages"
              parent="menu_todo_config"
              sequence="10"
              action="action_todo_stage" />

Odoo的缩写可以直接使用<menuitem>这个标签来代替<record mode='ir.ui.view'>

窗口动作(actions)

窗口动作通常与菜单以及按钮结合使用,它在GUI客户端中调度每个窗口。通过domian过滤器能显示记录中符合条件的子集,通过context可以传递参数。

    <act_window id="action_todo_stage"
                name="To-Do Task Stages"
                res_model="todo.task.stage"
                view_mode="tree,form"
                target="current"
                context="{'default_state': 'open'}"
                domain="[]"
                limit="80"
                />
    <act_window id="todo_app.action_todo_task"
                name="To-Do Tasks"
                res_model="todo.task"
                view_mode="tree,form,calendar,kanban,graph,pivot"
                target="current"
                context="{'search_default_filter_my_tasks': True}"
                />
    <act_window id="action_todo_task_stage"
                name="To-Do Task Stages"
                res_model="todo.task.stage"
                src_model="todo.task"
                multi="False"
                />

我们在'views/todo_menu.xml'中添加窗口动作,注意要把这些元素放在menu元素之前.窗口动作被存贮在'ir.actions.act_window'模型中,可使用缩写<act_window>.
上面代码第一个action我们打开了Task Stages模型.其中主要属性如下所列:

Context(上下文)跟domain

Context 数据

上下文数据是一个保存着会话信息的字典能够同时在用户界面跟业务后台中传递数据。

{'lang': 'en_US', 'tz': 'Europe/Brussels', 'uid': 1}
{'default_user_id' : uid}

设置一个默认的过滤器:

{'default_search_filter_my_tasks' : 1}

Domain表达式

domian表达式是用来过滤数据记录的。它本质是通过Odoo的ORM模型转换为SQL的WHERE子句。domain表达式的每个条件是一个三元素的元组格式:('field_name','operator','value')

& :逻辑 AND,条件间的默认关系。2个参数(后2个条件或者条件组合) ,例如:

['&', ('partner_id.coutnry_id.code', '=', 'CN'), ('partner_id.coutry_id.code', '=', 'US')]

这里的 & 就是把后面的2个条件通过AND组合起来也就是 A AND B,但是注意到这里说的是还有“条件组合”的情况,所以还有可能是

['&', ('partner_id.coutnry_id.code', '=', 'CN'), 
'&',('partner_id.coutry_id.code', '=', 'US'), ('partner_id.coutry_id.code', '=', 'GB')]

转换为一般的表示方法则是 A AND (B AND C),但是因为’&’是默认的逻辑关系,所以我们其实可以不用显式表示

[('partner_id.coutnry_id.code', '=', 'CN'),('partner_id.coutry_id.code', '=', 'US'), 
('partner_id.coutry_id.code', '=', 'GB')]

更多的Domain讨论可以在 Domain规则中看到


表单视图

form视图就像纸质文件一样,有着简单的布局。
我们可以对它进行布局的设置,现在让我们通过继承来扩展在todo_app中定义过的form视图.

处理相同类型的多个视图.

同一个模型可能会有多个视图,通过添加action的属性view_id,可以指定需要使用的视图.
Odoo为我们的模型提供了最为基础的form视图,当我们进行视图的修改后,Odoo会通过优先值来调用新视图.默认的视图优先级为16.

业务文档视图

正常业务使用中,许多记录都被记录在纸质文件上,例如发票,库存单.因此构建一张类似纸质文件的视图是十分有必要的.在我们的To-Do Task中,创建views/todo_views.xml文件.

    <record id="view_form_todo_task_ui"
            model="ir.ui.view">
        <field name="model">todo.task</field>
        <field name="priority">15</field>
        <field name="arch" type="xml">
            <form>
                <header>
                <!-- To add buttons and status widget-->
                </header>
                <sheet>
                   <!-- To add form content-->
                </sheet>
                <div class="oe_chatter">
                    <field name="message_follower_ids"
                           widget="mail_followers"/>
                    <field name="message_ids" widget="mail_thread"/>
                </div>
            </form>
        </field>
    </record>

业务文档视图通常使用3个主要区域。

header

通常我们在页面头部中放置动作按钮以及页面的生命周期状态。
通常action是通过放置button按钮来实现的。通常使用`class="oe_highlight"可以使其高亮显示
文档记录的生命周期使用'statusbar'这个窗口组件.一般使用'State'名称的selection字段或者一个'Stage'名字的多对一字段来表示文件记录当前的状态.
按照目前Odoo的趋势.逐渐使用Stage代替State来表示记录状态.
在todo_view.xml中扩展我们的header

                <header>
                    <field name="state" invisible="True"/>
                    <button name='do_toggle_done' type="object"
                            attrs="{'invisible':[('state','in',['draft'])]}"
                            string="Toggle Done"
                            class="oe_highlight"/>
                    <field name="stage_id"
                           widget="statusbar"
                           clickable="True"
                           options="{'fold_field':'fold'}"/>
                </header>

我们使用字段前,首先需要把该字段导入到view中。
上面的代码中。首先我们把记录的state字段设置为不可见,可以设置属性invisible="True"让字段在客户界面不显示.
下面定义一个button按钮来触发以前定义过的do_toggle_done方法.属性"attrs"的定义是指当文档记录的state状态为draft时隐藏该按钮.
clickable属性允许通过点击status bar来改变文档记录的stage字段值.

Sheet

sheet 标签中主要是实际数据存放的地方,它被设计成跟纸质文档类似的格式。它的主要结构:

标题跟副标题

<group>元素外的字段不会自动生成标注。所以我, 需要为这些标题元素添加label属性。Odoo的xml文件中可以使用html跟css语言。我们一般把标题放在<div class='oe_title'>标签下。

                <sheet>
                    <div class="oe_title">
                        <label for="name" class="oe_edit_only"/>
                        <h1><field name="name"/></h1>
                        <h3>
                            <span class="oe_read_only">By</span>
                            <label for="user_id" class="oe_edit_only"/>
                            <field name="user_id" class="oe_inline"/>
                        </h3>
                    </div>
                </sheet>

<label>的用法.for属性指定了需要的字段.class="oe_edit_only"表示只在编辑模式时显示该字段.

巧妙的按钮区域

右上角有一个按钮存放的区域。我们可以在其中添加按钮.

<div name="buttons" class="oe_right oe_button_box">
<!-- smart buttons here ...-->
</div>

我们表单的主要内容应该放置在<group>标签中.一个字段值跟一个字段标签通常需要两列,而一个<group>标签会在页面布局上插入两列。所以我们使用2个group标签,这样就可以构造左右两个字段的布局格式。

                    <group name="group_top">
                        <group name="group_left">
                            <field name="date_deadline"/>
                            <!--<separator string="Reference"/>-->
                            <field name="refers_to"/>
                        </group>
                        <group name="group_right">
                            <field name="tag_ids" widget="many2many_tags"/>
                            <field name="stage_state"/>
                        </group>
                    </group>

效果如下:

group效果

我们在定义group标签时,可以定义一个name属性,这有利于关联以及以后的扩展.

在group标签中我们可以使用col,colspan属性来对布局进一步的控制.

分页笔记本

另一种格式化内容的方式是使用notebook元素.包含多重分页节选。它能让不常用的数据在使用时才显示。
例子:

<notebook>
<page string="Whiteboard" name="whiteboard">
  <field name="docs"/>
</page>
<page>
<!--second page content -->
</page>
</notebook>

视图语义组件

刚才我们解释了如何结构化表单内容。现在我们来讲讲构造表单数据的部件。

Fields

视图中字段同样有许多属性,我们可以通过定义这些属性来重写模型中已经定义的字段的属性。

字段的标签

label元素通常用来控制字段在视图中的显示.

<label for="name" class="oe_edit_only" />

表示只有当处于编辑模式时才显示字段标签。
注意,在group元素内嵌中,我们还要设置nolabel="True".

关系字段

关系字段可用的属性有 context,domain.这些已经介绍过.还有一个options属性.我们知道,在关系型字段上,我们能够使用快速创建功能来快速创建一个新的关联模型记录,通过

options={'no_open': True, 'no_create' : True}

可以关闭快速创建功能.

字段窗口控件

字段根据自己的类型都有默认的窗口显示控件.当我们还可以自己来选择额外的窗口显示控件.

对于字符型字段:

关系型字段:

按钮

按钮支持下面的属性:

巧妙(Smart)按钮

就是表单结构中右上角的按钮小盒子.

image.png

在我们的app中,我们定义了了一个展示当前task总数的按钮,点击它会直接列出当前用户的task列表记录.

首先在 todo_model.py 文件中添加统计task的计算字段,

    def compute_user_todo_count(self):
        for task in self:
            task.user_todo_count = task.search_count([('user_id', '=', task.user_id.id)])

    user_todo_count = fields.Integer('User To-Do Count', compute='compute_user_todo_count')

然后在视图层添加button按钮

                    <div name="buttons" class="oe_right oe_button_box">
                        <button class="oe_stat_button"
                                type="action" icon="fa-tasks"
                                name="%(action_todo_task_button)d"
                                context="{'default_user_id': user_id}"
                                help="All to-dos for this user">
                            <field string="To-Dos" name="user_todo_count"
                                   widget="statinfo"/>
                        </button>

添加 smart buttons 时,有下列属性可以使用:

<div> User's To-dos </div>

下面来完善我们定义的action_todo_task_button 这个动作.它必须在button 之前定义

    <act_window id="action_todo_task_button"
                name="To-Do Tasks"
                res_model="todo.task"
                view_mode="tree,form,calendar,graph,pivot"
                domain="[('user_id','=',default_user_id)]"
    />

动态视图

视图元素提供了一些属性同样允许视图根据字段的值的变化来动态的展示对应的视图。

on change 事件

Odoo 提供的on change 机制通过监测字段的值的改变来对目标字段的值进行改变。举个例子,价格字段随着产品字段的选择的改变而产生变化来显示具体产品的价格。
从Odoo8.0版本以后,on change 可以直接在模型python代码中实现。通过@api.onchange('field1', 'field2') 来实现.

动态属性

动态属性能够更好的通过 on change 机制来对用户视图上元素的可视化进行控制.

视图模式

    <record id="view_tree_todo_task" model="ir.ui.view">
        <field name="name">To-do Task tree</field>
        <field name="model">todo.task</field>
        <field name="arch" type="xml">
            <tree colors="red:is_done==True">
                <field name="name"/>
                <field name="is_done"/>
            </tree>
        </field>
    </record>

对应属性:

  1. default_order : 默认的排序规则.
  2. create,delte,edit : 如果设置为 false ,让对应的视图上的动作失效.
  3. editable : 让记录能够在列表视图中直接被修改.
    列表视图中,数字型字段能够通过使用 sum, avg, min, max 属性来对每列的数据进行一个统计操作。
<field name="amount" sum="Total Amount"/>
    <record id="todo_app.view_filter_todo_task"
            model="ir.ui.view">
        <field name="model">todo.task</field>
        <field name="arch" type="xml">
            <search>
                <field name="name" />
                <field name="user_id"/>
                <filter name="filter_not_done" string="Not Done"
                       domain="[('is_done','=',False)]"/>
                <filter name="filter_done" string="Done"
                       domain="[('is_done','!=',False)]"/>
                <separator/>
                <filter name="group_user" string="By User"
                        context="{'group_by':'user_id'}"/>
            </search>
        </field>
    </record>

我们使用了 nameuser_id 字段进行搜索.
搜索视图属性:

  1. name : 标识了使用的字段.
  2. string : 字符标识
  3. operator : 操作方式,数字类型字段默认为=, 其他的是ilike.
  4. filter_domain : 过滤规则.提供一个可以选择的现成过滤器小方块显示在搜索栏下拉菜单中.
  5. groups : 根据使用者的分组决定搜索权限.

对于过滤器元素.以下属性可以使用:

  1. name : 定义了过滤器的标识id.
  2. string : 过滤器在视图中的字符标识.
  3. domain : domain过滤规则.
  4. context : 上下文传递数据.
  5. groups : 根据当前用户分组权限决定是否显示本过滤器.
   <record id="view_calendar_todo_task" model="ir.ui.view">
       <field name="model">todo.task</field>
       <field name="arch" type="xml">
           <calendar date_start="date_deadline" color="user_id"
                     display="[name], Stage [stage_id]">
               <field name="name"></field>
               <field name="stage_id"/>
           </calendar>
       </field>
   </record>

日历视图属性:

  1. date_start : 开始日期。
  2. date_end : 结束日期.
  3. date_delay : 持续时间,可以用来代替date_end .很好理解,end - start = delay嘛。
  4. all_day : 一个bool字段来决定是否是全天持续事件.
  5. color : 根据分组来设置一个显示颜色
  6. display : 显示的格式. 代码中就是显示记录的名字跟阶段状态。
  7. mode :显示模式,默认是 day, week, month
    effort_estimate = fields.Integer('effort estimate')
    <record id="view_graph_todo_task" model="ir.ui.view">
        <field name="model">todo.task</field>
        <field name="arch" type="xml">
            <graph type="bar">
                <field name="stage_id"/>
                <field name="effort_estimate" type="measure"/>
            </graph>
        </field>
    </record>

图表的type 有3个可选 bar,pie,line

添加数据透视表

    <record id="view_pivot_todo_task" model="ir.ui.view">
        <field name="model">todo.task</field>
        <field name="arch" type="xml">
            <pivot>
                <field name="stage_id" type="col"/>
                <field name="user_id"/>
                <field name="date_deadline" interval="week"/>
                <field name="effort_estimate" type="measure"/>
            </pivot>
        </field>
    </record>
上一篇 下一篇

猜你喜欢

热点阅读