在儀表板中可視化數據?

重要

本教程是 開始 教程的擴展。請確保您已經完成了該教程,并使用您構建的 estate 模塊作為本教程中練習的基礎。如果您想從一個干凈的基礎開始,請從 technical-training-solutions 存儲庫中獲取 16.0-core 分支。

“Dashboard” 這個術語在 Odoo 中用于顯示數據的對象,但涉及不同的實現方式。本教程僅關注用于提供聚合數據可視化的企業視圖。它們可以作為“view_mode”添加到現有模型中(即可以通過視圖按鈕在視圖右上角切換到的視圖),但它們也經常用作專門為數據可視化定制的特殊模型的視圖。您可能會聽到這些特殊視圖被稱為 SQL 視圖。

需要注意的是,在Odoo社區中有一個”Dashboard”應用程序。該應用程序允許用戶創建自己的數據視圖,但是自定義僅對每個用戶可見,并且只能在”Dashboard”應用程序中查看。從技術上講,使用此“board”模塊可以制作全局儀表板,但作為企業視圖更容易。此外,它看起來更漂亮,并具有“board”中不可用的額外功能。Odoo中還存在其他一些儀表板,但它們是定制的,超出了本教程的范圍。

有關此主題的文檔可以在 儀表板 中找到。

文件結構?

你可能已經猜到了,由于儀表板視圖是企業視圖,因此它們必須依賴于企業模塊。企業模塊是 web_dashboard 。不要忘記將其添加到您的清單文件中!將旨在用作您模塊的某個模型(在 model 文件夾中)的 view_mode 的儀表板添加到視圖目錄中是標準做法(即包含同一模型的其他視圖的同一文件)。

創建一個單獨的企業版模塊,以向社區版模塊添加額外的企業版視圖和功能是標準做法。這與 第14章:與其他模塊交互 中介紹的模塊鏈接技術類似。不同之處在于,我們不是鏈接兩個不同的模塊,而是擴展我們的 estate 模塊。我們通過創建一個新模塊,并將社區版模塊及其必要的企業版模塊依賴項添加到其清單中來實現這一點。你通常會在模塊的目錄名稱中看到 “enterprise”。為了使本教程簡單,我們將在現有的 estate 模塊中添加儀表板。

SQL Views有兩個部分:它們的xml文件(不要忘記將其添加到您的清單文件中)和它們的Python文件(不要忘記將其添加到適當的 __init.py__ 文件中)。前者與 view_mode xml具有相同的格式,而后者包含自定義模型和SQL代碼以填充其字段。將SQL視圖文件添加到 report/ 目錄是標準的。在SQL視圖文件名中包含“report”也很常見。您可能會想知道為什么我們將文件放在報告目錄中?我們之前看到儀表板用于數據可視化,因此它不可編輯。您可以將儀表板視為交互式報告,您可以單擊統計數據、圖表和圖表以查看對其做出貢獻的具體數據。請注意,將 PDF報告模板 的xml代碼存儲在報告目錄中也是標準的。

預計您的工作目錄看起來會像這樣:

estate
├── models
│   ├── *.py
│   └── __init__.py
├── report
│   ├── __init__.py
│   ├── estate_report.py
│   └── estate_report_views.xml
├── security
│   └── ir.model.access.csv
├── views
│   ├── *.xml
│   └── estate_property_views.xml
├── __init__.py
└── __manifest__.py

儀表板視圖?

注解

目標 : 在本節結束時,我們將擁有一個顯示不同屬性統計信息的新儀表板視圖。

基本儀表板視圖

儀表板可以以不同的方式顯示數據,包括:

  • 顯示一個字段的 聚合

  • 公式 中使用聚合字段

  • 使用 小部件

  • 將另一個 視圖 用作子視圖

使用這些選項,我們可以為我們的房地產示例提供許多有用的統計數據和可視化效果。在完成本節練習時,可以參考完整的示例,鏈接如下: `在此查看 <https://github.com/odoo/enterprise/blob/6fd3244ae168dc73c348a9c1870796e89d8ef594/crm_enterprise/views/crm_lead_views.xml#L106-L133>`__(受限的github存儲庫鏈接)。

數據?

為了充分享受我們的儀表板視圖,我們需要良好的測試數據來填充它。測試數據將允許我們檢查結果的外觀和統計數據是否正確。測試時最好使用覆蓋大部分或所有預期用例的數據,但也易于驗證統計數據是否正確。在我們的目標案例中,我們正在查看計數、總和、平均值、最小值和最大值統計數據,因此我們儀表板的一個良好的代表性集合是:

  • 至少包含3個不同類型的房產,包括預期價格和平均居住面積。

  • 至少有1個已售出的物業和1個已取消的物業

如果你還沒有這樣的數據集,你可以選擇:

  • 完成 定義模塊數據 (如果您還沒有完成)并將額外的情況添加到您的演示數據中(您可能需要創建一個新的數據庫來加載演示數據)。

  • 在數據庫中手動創建數據。

  • 將此 數據文件 復制到您的 estate 模塊中的一個名為 data 的新目錄中,并將 這些行 復制到您的 __manifest__.py 文件中(您可能需要創建一個新的數據庫來加載演示數據)。

點擊瀏覽您的數據庫數據,確保它符合您的預期。當然,您可以在編寫儀表板代碼后添加數據,然后測試您的視圖是否按預期工作。

聚合?

構建儀表板視圖與之前在 第七章:基本視圖 中所做的非常相似。對于儀表板視圖,我們使用 dashboard 根元素,并從其可能的標記中進行選擇(請參閱 儀表板 文檔中的所有可能性及其屬性)。因此,一個簡單的儀表板示例如下:

<dashboard>
    <group>
        <aggregate name="min_expected_price" string="Min Expected Price" field="expected_price"
            group_operator="min" help="Lowest expected price."/>
    </group>
</dashboard>

在這個例子中, <group> 添加了樣式, <aggregate> 聲明了一個聚合。我們指定要聚合的 field ,要顯示的 string ,以及如何使用 group_operator 屬性進行聚合。 group_operator 可以使用任何有效的 PostgreSQL 聚合函數,還可以使用特殊的 Odoo 定義的 count_distinct 。

希望你還記得如何將視圖添加到窗口操作的 view_mode (提示,在 第六章:終于有一些界面可以玩了 中有介紹)?,F在讓我們制作一些儀表板!

Exercise

創建一個儀表盤視圖。

  • 創建一個聚合值的儀表盤,針對 estate.property 模型。您可以查看本節的 **目標 ** 來獲取一些靈感。請記得檢查您的統計數據是否按照您的預期計算,并注意計算出的值會考慮任何應用的視圖過濾器!

  • 獎勵:添加一些需要 domain 才有意義的聚合(記住 domain 也在 第七章:基本視圖 中介紹過)。

餅圖?

使用 <widget> 元素向儀表板添加餅圖非常簡單。以下是一個示例:

<dashboard>
    <group>
      <widget name="pie_chart" title="Property Types" attrs="{'groupby': 'property_type_id'}"/>
    </group>
</dashboard>

在這個例子中,我們指定了使用 pie_chart 小部件,使用 name 屬性和餅圖的 title ,并且我們按照屬性類型進行分組。

Exercise

添加一些餅圖。

  • 將本節的 **目標 ** 中的餅圖添加到您的儀表板中。提示:如果您想按物業類型分組顯示銷售價格,則需要將 'measure': selling_price 添加到您的餅圖 attrs 中。

  • 將鼠標懸停在餅圖上并單擊以檢查圖表計數值,不要忘記篩選器也會應用于圖表。

  • 獎勵:為您的銷售價格餅圖添加一個域,僅包括“已售出”的房產(即不包括“已接受報價”的房產)。請注意,由于它被聲明為 attrs 的一部分,因此 ' 需要進行轉義。

子視圖?

類似于我們可以在表單視圖中使用列表視圖(我們在 第八章:模型之間的關系 中自動看到了這一點),我們可以在我們的儀表板視圖中添加其他視圖。最常添加的是透視圖和圖形視圖,但群體視圖也是一種選擇。只有子視圖的儀表板如下:

<dashboard>
    <view type="graph"/>
    <view type="pivot"/>
</dashboard>

<view> 元素可以添加 ref 屬性來使用特定的 XML id。如果沒有為圖表或透視圖提供 XML id,則將使用默認視圖。如果沒有特定的 XML id,則儀表板中的 cohort 視圖將無法工作。如果您已經創建了其中一些視圖,則可以將它們添加到您的儀表板中!示例圖表和透視圖包含在 解決方案代碼 中,您也可以使用它們。

Exercise

添加子視圖。

  • 將圖表和數據透視表添加到您的儀表板中。嘗試調整子視圖與餅圖和聚合值的布局,并參考本節的 目標 以獲取常用布局。記得檢查子視圖是否按預期顯示數據(是的,它們也受過濾器的影響?。?。

SQL 視圖?

警告

本節需要您具備基本的 SQL 知識。如果您對 SQL 知識了解很少或者沒有了解過,那么 這個教程是一個不錯的開始,并且這些 練習 對于需要復習或者額外練習的人來說也很有用。

注解

目標 :本節結束時,我們將擁有一個新的 SQL 視圖,顯示不同的房產統計信息。

SQL視圖

有時我們需要展示超出模型已有數據的內容。我們可以添加很多存儲的計算或相關字段(非存儲字段無法聚合或在餅圖中顯示),但僅為此目的存儲一堆字段是不切實際的。我們可以添加自定義的SQL視圖來最小化計算負載并保持模型干凈無需的字段。

模型?

我們將從較難的部分開始:我們的特殊報告模型。這個文件與任何其他模型一樣開始,只是我們添加了兩個屬性 _auto_rec_name

from odoo import fields, models, tools


class EstateReport(models.Model):
    _name = 'estate.report'
    _description = "Stock Report"
    _rec_name = 'id'
    _auto = False

_auto = False 表示我們不想將模型存儲在數據庫中,而是通過覆蓋 BaseModel.init() 方法來創建自定義表。 _rec_name 表示模型的哪個字段表示記錄的名稱 (即在打開記錄的表單視圖時將使用的名稱)。在這種情況下,我將其保留為 ‘id’,因為我們的 屬性報價沒有名稱。我們稍后需要 tools 導入 (即 odoo/odoo/tools ,其中包含各種有用的 輔助方法,您可能會在將來使用)。請注意,將 report 包含在模型名稱中是標準做法。

記住,你的新模型需要添加到你的安全文件中,就像你在 第五章:安全性 - 簡介 中學到的一樣!

然后我們像定義任何其他模型一樣定義我們需要的儀表板字段(就像您在 第四章:模型和基本字段 中學到的那樣),只是每個字段都是 readonly=True 。畢竟,我們的模型僅用于只讀目的。

現在我們覆蓋之前提到的 BaseModel.init() 方法:

def init(self):
    tools.drop_view_if_exists(self.env.cr, self._table)
    self.env.cr.execute("""CREATE or REPLACE VIEW %s as (
                           SELECT
                              %s
                           FROM
                              %s
          )""" % (self._table, self._select(), self._from()))

我們使用 tools.drop_view_if_exists 來確保我們不會創建沖突的視圖,然后執行 SQL 查詢。將查詢的不同部分分離出來以便于模型擴展是標準的做法。具體如何在方法之間拆分查詢并沒有標準化,但通常至少會看到 _select_from 方法(或類似的方法),當然所有這些方法都將返回字符串。SELECT 中的列將填充我們模型的字段,因此請確保您的列名與字段名匹配或使用與之匹配的別名。

Exercise

創建報告模型。

  • 創建一個包含以下字段的報告模型:

    字段

    類型

    備注

    編號

    整數

    對應于 estate.property.offerid

    報價狀態

    選擇

    等于 estate.property.offerstate 選項

    屬性ID

    多對一

    estate.property

    物業狀態

    選擇

    等于 estate.propertystate 選項

    屬性類型 ID

    多對一

    estate.property.type

    并編寫必要的 SQL 查詢以填充字段(提示,您將需要 2 個 JOIN)。

    在我們創建視圖之前,您將無法檢查您的模型是否正確,但是您可以直接在數據庫中檢查您的查詢結果是否符合您的預期。如果您在這個練習中遇到困難,那么可以參考 `這里的示例<https://github.com/odoo/odoo/blob/7417d8fc138b9de550bc631435bcc08628c29bed/addons/crm/report/crm_activity_report.py>`__。

視圖?

現在我們有了模型,可以制作它的儀表板視圖。制作方式與其他視圖沒有區別,只是文件在“report”文件夾中。由于它是一個沒有與其他模型關聯的新模型,我們還需要添加一個新的菜單項來查看我們的儀表板。通常,SQL視圖會添加在名為“Reporting”的一級菜單下(因為它是報告,驚喜?。?。你還記得如何添加“menuitem”嗎?如果不記得,請重新查看 第六章:終于有一些界面可以玩了 。

Exercise

創建報告視圖。

  • 在本節的 目標 中重新創建儀表板。提示:它使用了 formula 元素,而我們之前的儀表板不需要它。

  • 獎勵:為您的新報告模型創建“列表”和“表單”視圖,這樣當您點擊餅圖時,我們就不必看到丑陋的默認視圖了。

額外提示?

提示1 SQL視圖中常見的一個錯誤是沒有考慮由于表JOIN而導致某些數據的重復。例如,在我們的 目標 中,我們有一個餅圖顯示房源的屬性類型。我們可能會想添加一個類似的餅圖,只包括已取消的房源,這樣我們認為我們只計算每種屬性類型的已取消房源數量。實際上,我們仍然在查看每個房源的所有報價,因此任何有多個報價的房源都將按報價計算。通過單擊餅圖查看其列表視圖,可以輕松地檢查此示例:

餅圖列表視圖

但是對于平均聚合或使用子視圖(如透視圖)等情況,很容易忽略這個錯誤。當您的測試數據不足時,也很容易忽略這個錯誤。要將按物業類型取消的物業數量餅圖添加到此報告中,我們要么必須使用一個技巧(對于本教程來說太高級了),要么就將其從此報告中排除。

提示2 如果您有一個不想作為度量(即在您的透視表或圖形視圖中)的字段,則可以將 store=False 添加到它,它將不會顯示。

提示 3 如果您有一個依賴于上下文的 SQL 視圖,則可以設置 _table_query 屬性,而不是覆蓋 BaseModel.init() 方法:

@property
def _table_query(self):
    return 'SELECT %s FROM %s' % (self._select(), self._from())

選擇( select )和來源( from )方法保持不變。

這里有一個示例,它依賴于當前選擇的公司(在多公司環境中)上下文來確定要使用的貨幣匯率,以便在所選公司具有不同貨幣時準確顯示金額。