建立一個Odoo Module (五)- Advanced Views

Advanced Views

Tree views

Tree views 可以通過增加 attribute 來提供更深度的定製化

  • decoration-{$name}
    允許針對不同的record的特定值,來修改record 對應 的樣式
    值爲普通的python 表達式,此表達式將會依次作用於每一個record,record 的各項屬性,將會作爲 context 傳入此表達式,如果爲表達式值爲 True,對應行的樣式就會修改。除了 record 的各項屬性,Odoo也會自動傳入,uidcurrent_date(as string yyyy-MM-dd 傳入)
    {$name} 可以是 bf( font-weight: bold ) it (font-style: italic),也可以是Bootstrap 的一些樣式(danger, info, muted, primary, success, warning
<tree string="Idea Categories" decoration-info="state=='draft'"
    decoration-danger="state=='trashed'">
    <field name="name"/>
    <field name="state"/>
</tree>
  • editable
    值爲 "top" 或者 "bottom",可以讓 Tree view 就地進入編輯狀態,而不是點擊進入 Form view 去修改,這兩個就是 新的record 出現的位置。

練習 5-1
將 session tree 添加一定的色彩,當session duration < 5是,這一行 顯示爲 blue, duration >15 , 將其顯示爲 red
openacademy/views/openacademy.xml

            <field name="name">session.tree</field>
            <field name="model">openacademy.session</field>
            <field name="arch" type="xml">
                <tree string="Session Tree" decoration-info="duration&lt;5" decoration-danger="duration&gt;15"> <!-- 修改 -->
                    <field name="name"/>
                    <field name="course_id"/>
                    <field name="duration" invisible="1"/> <!-- 修改 -->
                    <field name="taken_seats" widget="progressbar"/>
                </tree>
            </field>

Calendars

將 record 以 calendar events 的方式展現,常用的 attributes 有:

  • color
    The name of the field used for color segmentation. Colors are automatically distributed to events, but events in the same color segment (records which have the same value for their @color field) will be given the same color.

  • date_start
    record’s field holding the start date/time for the event

  • date_stop (可選)
    record’s field holding the end date/time for the event

field (to define the label for each calendar event)

<calendar string="Ideas" date_start="invent_date" color="inventor_id">
    <field name="name"/>
</calendar>

練習 5-2
給session 添加一個 calendar view,

  • 添加一個 computed field end_date,根據 start_dateduration 計算而來
  • 添加 calendar view

openacademy/models.py

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

from datetime import timedelta # new line
from openerp import models, fields, api, exceptions

class Course(models.Model):
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

    taken_seats = fields.Float(string="Taken seats", compute='_taken_seats')
    end_date = fields.Date(string="End Date", store=True,
        compute='_get_end_date', inverse='_set_end_date') # new field

    @api.depends('seats', 'attendee_ids')
    def _taken_seats(self):
                },
            }
    # new add
    @api.depends('start_date', 'duration')
    def _get_end_date(self):
        for r in self:
            if not (r.start_date and r.duration):
                r.end_date = r.start_date
                continue

            # Add duration to start_date, but: Monday + 5 days = Saturday, so
            # subtract one second to get on Friday instead
            start = fields.Datetime.from_string(r.start_date)
            duration = timedelta(days=r.duration, seconds=-1)
            r.end_date = start + duration

    def _set_end_date(self):
        for r in self:
            if not (r.start_date and r.end_date):
                continue

            # Compute the difference between dates, but: Friday - Monday = 4 days,
            # so add one day to get 5 days instead
            start_date = fields.Datetime.from_string(r.start_date)
            end_date = fields.Datetime.from_string(r.end_date)
            r.duration = (end_date - start_date).days + 1
    # end
    @api.constrains('instructor_id', 'attendee_ids')
    def _check_instructor_not_in_attendees(self):
        for r in self:

openacademy/views/openacademy.xml

            </field>
        </record>

        <!-- calendar view 新增-->
        <record model="ir.ui.view" id="session_calendar_view">
            <field name="name">session.calendar</field>
            <field name="model">openacademy.session</field>
            <field name="arch" type="xml">
                <calendar string="Session Calendar" date_start="start_date"
                          date_stop="end_date"
                          color="instructor_id">
                    <field name="name"/>
                </calendar>
            </field>
        </record>

        <record model="ir.actions.act_window" id="session_list_action">
            <field name="name">Sessions</field>
            <field name="res_model">openacademy.session</field>
            <field name="view_type">form</field>
            <field name="view_mode">tree,form,calendar</field> <!-- 修改 -->
        </record>

        <menuitem id="session_menu" name="Sessions"

Search views

search view 中的 field 可以有一個 filter_domain 屬性,可以覆蓋掉 Odoo自動爲這個field設置的 search domain。 在 filter_domain 中 self 代表的就是 用戶在搜索框中輸入的 數據。
search view 中也可以有 <filter> 元素, 用以預先定義一些快捷搜索,在其中必須有以下屬性中的一個

  • domain 就給 search 提供篩選條件
  • context 給當前 search 提供 context ,通常使用 group_by ,來分組搜素結果。
<search string="Ideas">
    <field name="name"/>
    <field name="description" string="Name and description"
           filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"/>
    <field name="inventor_id"/>
    <field name="country_id" widget="selection"/>

    <filter name="my_ideas" string="My Ideas"
            domain="[('inventor_id', '=', uid)]"/>
    <group string="Group By">
        <filter name="group_by_inventor" string="Inventor"
                context="{'group_by': 'inventor_id'}"/>
    </group>
</search>

如果想要在 action 中不使用 默認的 search view, 可以明確指定 search_view_id 的值
action 中同樣可以設定 search view 的初始行爲,只需要在 action 的 context 中傳入一定的參數即可,如: search_default_field_name


練習 5-3

  • 添加一個button,使其可以將 當前登錄用戶的 course 顯示出來,再將其設置爲默認。
  • 添加一個button,使course 可以根據用戶 分組顯示

openacademy/views/openacademy.xml

                <search>
                    <field name="name"/>
                    <field name="description"/>
                    <!-- 添加 -->
                    <filter name="my_courses" string="My Courses"
                            domain="[('responsible_id', '=', uid)]"/>
                    <group string="Group By">
                        <filter name="by_responsible" string="Responsible"
                                context="{'group_by': 'responsible_id'}"/>
                    </group>
                    <!-- 結束 -->
                </search>
            </field>
        </record>
            <field name="res_model">openacademy.course</field>
            <field name="view_type">form</field>
            <field name="view_mode">tree,form</field>
            <field name="context" eval="{'search_default_my_courses': 1}"/> <!-- 添加 -->
            <field name="help" type="html">
                <p class="oe_view_nocontent_create">Create the first course
                </p>

Gantt

由於 Odoo community 版本不支持 gantt, 所以我就不翻譯了。
https://github.com/odoo/odoo/issues/9640

Graph views

Graph view 提供了一種全局的概覽 以及 數據的分析,root element 是 <graph>
它有4種展現方式,修改默認的展現方式可以通過設置 type 屬性

  • Bar (默認)
    在 bar chart 中,第一個是用來橫向分組的,剩餘的都是在 第一個分組的情況下,展現各自的數據。
    默認的 bar 是 side-by-side, 但可以在 <graph stacked='True'> 來修改。

  • Line 2D 線

  • Pie 2D 餅圖

Graph view 裏面的 <field> 都會被強制賦予 type 屬性,兩種選擇:

  • row (默認) the field should be aggregated by default
  • measure the field should be aggregated rather than grouped on
<graph string="Total idea score by Inventor">
    <field name="inventor_id"/>
    <field name="score" type="measure"/>
</graph>

注意: graph 不支持 computed field, 除非 此 computed field 設置了 store=True 屬性


練習 5-4
在 給 session 添加一個graph view,在每個 course 下,顯示 attendees number

  • 添加 attendees_count which computed field but stored
  • add 相關view

openacademy/models.py

    hours = fields.Float(string="Duration in hours",
                         compute='_get_hours', inverse='_set_hours')
    # 新增
    attendees_count = fields.Integer(
        string="Attendees count", compute='_get_attendees_count', store=True)

    @api.depends('seats', 'attendee_ids')
    def _taken_seats(self):
        for r in self:
        for r in self:
            r.duration = r.hours / 24
    # 新增
    @api.depends('attendee_ids')
    def _get_attendees_count(self):
        for r in self:
            r.attendees_count = len(r.attendee_ids)

    @api.constrains('instructor_id', 'attendee_ids')
    def _check_instructor_not_in_attendees(self):
        for r in self:

openacademy/views/openacademy.xml

            </field>
        </record>
        # 新增
        <record model="ir.ui.view" id="openacademy_session_graph_view">
            <field name="name">openacademy.session.graph</field>
            <field name="model">openacademy.session</field>
            <field name="arch" type="xml">
                <graph string="Participations by Courses">
                    <field name="course_id"/>
                    <field name="attendees_count" type="measure"/>
                </graph>
            </field>
        </record>

        <record model="ir.actions.act_window" id="session_list_action">
            <field name="name">Sessions</field>
            <field name="res_model">openacademy.session</field>
            <field name="view_type">form</field>
            <field name="view_mode">tree,form,calendar,gantt,graph</field> # 修改
        </record>

        <menuitem id="session_menu" name="Sessions"

Kanban

通常用來顯示,任務進度,生產流程等,root element是 <kanban>
kanban view 將一對的 cards 已 coloumn 的形式展現,每一 card 代表一個 record ,每一個 column 都代表 按照 某個 field 的分類。
比如, project 可能按照 stage 狀態被分類(column 就是 stage),或者被 負責人responsible (column 就是 user), 等。
kanban view 爲每一個 card 定義了類似 form view的 效果,當然也支持原生HTML 和 QWeb


練習 5-5

  • 添加一個 integer color 字段到 Session model
  • 添加kanban view, update action

openacademy/models.py

    duration = fields.Float(digits=(6, 2), help="Duration in days")
    seats = fields.Integer(string="Number of seats")
    active = fields.Boolean(default=True)
    color = fields.Integer() # new line

    instructor_id = fields.Many2one('res.partner', string="Instructor",
        domain=['|', ('instructor', '=', True),

openacademy/views/openacademy.xml

        </record>
        <!-- 新增 -->
        <record model="ir.ui.view" id="view_openacad_session_kanban">
            <field name="name">openacad.session.kanban</field>
            <field name="model">openacademy.session</field>
            <field name="arch" type="xml">
                <kanban default_group_by="course_id">
                    <field name="color"/>
                    <templates>
                        <t t-name="kanban-box">
                            <div
                                    t-attf-class="oe_kanban_color_{{kanban_getcolor(record.color.raw_value)}}
                                                  oe_kanban_global_click_edit oe_semantic_html_override
                                                  oe_kanban_card {{record.group_fancy==1 ? 'oe_kanban_card_fancy' : ''}}">
                                <div class="oe_dropdown_kanban">
                                    <!-- dropdown menu -->
                                    <div class="oe_dropdown_toggle">
                                        <i class="fa fa-bars fa-lg"/>
                                        <ul class="oe_dropdown_menu">
                                            <li>
                                                <a type="delete">Delete</a>
                                            </li>
                                            <li>
                                                <ul class="oe_kanban_colorpicker"
                                                    data-field="color"/>
                                            </li>
                                        </ul>
                                    </div>
                                    <div class="oe_clear"></div>
                                </div>
                                <div t-attf-class="oe_kanban_content">
                                    <!-- title -->
                                    Session name:
                                    <field name="name"/>
                                    <br/>
                                    Start date:
                                    <field name="start_date"/>
                                    <br/>
                                    duration:
                                    <field name="duration"/>
                                </div>
                            </div>
                        </t>
                    </templates>
                </kanban>
            </field>
        </record>

        <record model="ir.actions.act_window" id="session_list_action">
            <field name="name">Sessions</field>
            <field name="res_model">openacademy.session</field>
            <field name="view_type">form</field>
            <field name="view_mode">tree,form,calendar,gantt,graph,kanban</field> <!-- 修改 -->
        </record>

        <menuitem id="session_menu" name="Sessions"
                  parent="openacademy_menu"

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章